[破碎的状态] [-64] NOI 2015 品酒大会
这一题是个后缀数组
立下flag:在最近的8天里,每日blog至少一更碎碎念
所以,这一题就是求出lcp以后并查集乱搞就行了..
考场上并没想到lcp也是可惜,另外n log2n看起来不是完全不能过..至少uoj和bzoj都过了,lg挂了不明为何
下次写个O(n log n)或者O(n)的试试吧..
lcp的性质也真是神奇..长见识了..
反正这样就是过了..
解法:
1,求lcp
2,倒序求答案
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<time.h>
#include<bitset>
#include<vector>
#include<memory>
#include<utility>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
int x;
int y;
int id;
friend bool operator < (const node &a,const node &b)
{
return a.y<b.y;
}
};
node b[300005];
char a[300005];
int n;
int c[300005];
int val[300005];
void suffix_sort(int xx)
{
if (xx>=n) return;
int i;
for (i=0;i<n;i++)
{
if ((i==0)||(b[i].x>b[i-1].x)||(b[i].y>b[i-1].y))
{
c[b[i].id]=i;
}
else
{
c[b[i].id]=c[b[i-1].id];
}
}
for (i=0;i<n;i++)
{
b[i].x=c[b[i].id];
if (b[i].id+xx<n)
{
b[i].y=c[b[i].id+xx];
}
else
{
b[i].y=-1;
}
}
int last=0;
for (i=1;i<n;i++)
{
if (b[i].x!=b[i-1].x)
{
sort(b+last,b+i);
last=i;
}
}
sort(b+last,b+i);
suffix_sort(xx*2);
}
int lcp[300005];
struct nodes
{
int size;
int id;
int max_val1;
int max_val2;
int min_val1;
int min_val2;
nodes * last;
nodes * next;
};
struct lcps
{
int num1;
int num2;
int times;
friend bool operator < (const lcps &a,const lcps &b)
{
return a.times>b.times;
}
};
lcps g[300005];
nodes f[300005];
const int inf=1000000007;
long long ans1[300005];
long long ans2[300005];
int father[300005];
void link(int x,int y,int i)
{
int temp=x;
for (;;)
{
if (father[temp]==-1) break;
temp=father[temp];
}
for (;x!=temp;)
{
int now=father[x];
father[x]=temp;
x=now;
}
temp=y;
for (;;)
{
if (father[temp]==-1) break;
temp=father[temp];
}
for (;y!=temp;)
{
int now=father[y];
father[y]=temp;
y=now;
}
ans1[i]-=((long long)f[x].size*(f[x].size-1)/2);
ans1[i]-=((long long)f[y].size*(f[y].size-1)/2);
f[x].size+=f[y].size;
ans1[i]+=((long long)f[x].size*(f[x].size-1)/2);
if (f[y].max_val1>f[x].max_val1)
{
f[x].max_val2=f[x].max_val1;
f[x].max_val1=f[y].max_val1;
}
else if (f[y].max_val1>f[x].max_val2)
{
f[x].max_val2=f[y].max_val1;
}
if (f[y].max_val2>f[x].max_val2)
{
f[x].max_val2=f[x].max_val2;
}
if (f[y].min_val1<f[x].min_val1)
{
f[x].min_val2=f[x].min_val1;
f[x].min_val1=f[y].min_val1;
}
else if (f[y].min_val1<f[x].min_val2)
{
f[x].min_val2=f[y].min_val1;
}
if (f[y].min_val2<f[x].min_val2)
{
f[x].min_val2=f[x].min_val2;
}
long long t=max((long long)f[x].max_val1*f[x].max_val2,(long long)f[x].min_val1*f[x].min_val2);
if (ans1[i]==1)
{
ans2[i]=t;
}
else if (ans2[i]<t)
{
ans2[i]=t;
}
f[x].next=f[y].next;
f[y].next->last=&f[x];
father[y]=x;
}
int main()
{
#ifdef absi2011
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d",&n);
scanf("%s",a);
n=strlen(a);
int i;
for (i=0;i<n;i++)
{
b[i].y=a[i];
b[i].id=i;
scanf("%d",&val[i]);
}
sort(b,b+n);
suffix_sort(1);
for (i=0;i<n;i++)
{
if ((i==0)||(b[i].x>b[i-1].x)||(b[i].y>b[i-1].y))
{
c[b[i].id]=i;
}
else
{
c[b[i].id]=c[b[i-1].id];
}
}
for (i=0;i<n;i++)
{
//printf("%d ",b[i].id+1);
int last;
if ((i==0)||(lcp[i-1]==0))
{
last=0;
}
else
{
last=lcp[i-1]-1;
}
if (c[i]==0) continue;
for (;a[last+i]==a[last+b[c[i]-1].id];last++) ;
lcp[i]=last;
}
for (i=1;i<n;i++)
{
g[i].num1=b[i-1].id;
g[i].num2=b[i].id;
g[i].times=lcp[b[i].id];
}
sort(g+1,g+n);
int j;
nodes temp;
memset(father,-1,sizeof(father));
for (j=0;j<n;j++)
{
i=b[j].id;
if (j!=0) f[i].last=&f[b[j-1].id];
if (j!=n-1) f[i].next=&f[b[j-1].id];
f[i].size=1;
f[i].max_val1=val[i];
f[i].max_val2=-inf;
f[i].min_val1=val[i];
f[i].min_val2=inf;
}
f[b[0].id].last=&temp;
f[b[n-1].id].next=&temp;
int now=1;
for (i=n-1;i>=0;i--)
{
ans1[i]=ans1[i+1];
ans2[i]=ans2[i+1];
for (;now<n;)
{
if (g[now].times<i) break;
link(g[now].num1,g[now].num2,i);
now++;
}
}
ios::sync_with_stdio(false);
for (i=0;i<n;i++)
{
cout<<ans1[i]<<" "<<ans2[i]<<'\n';
}
return 0;
}
评论 (0)