您的位置:首页 > 其它

BZOJ4199: [Noi2015]品酒大会

2016-06-26 20:01 330 查看
后缀数组height排序后并查集合并

也就是height较大的合并不影响较小的

num[i]=num[i+1] ans[i]=ans[i+1]

合并时,num+=sz[x]*sz[y],ans=max(mn[x]*mn[y],mx[x]*mx[y],ans)

这种思路适应于求点对,还可以考虑启发式合并

后缀数组还有的常见思路就是二分,height分组

#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define ll long long
ll sum
,ans
;
int n,val
,fa
,mx
,mn
,sz
;
int m=256,c
,sa
,rk
,h
,t1
,t2
;
char s
;
struct Node{
int h,x,y;
}g
;
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void get_sa(int n){
int *x=t1,*y=t2;
for(int i=0;i<m;i++)c[i]=0;
for(int i=0;i<n;i++)c[x[i]=s[i]]++;
for(int i=0;i<m;i++)c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k;i<n;i++)y[p++]=i;
for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(int i=0;i<m;i++)c[i]=0;
for(int i=0;i<n;i++)c[x[y[i]]]++;
for(int i=0;i<m;i++)c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);x[sa[0]]=0;p=1;
for(int i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n)break;
m=p;
}
}
void get_height(int n){
for(int i=0;i<n;i++)rk[sa[i]]=i;
int k=0;
for(int i=0;i<n;i++){
if(k)k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k])k++;
h[rk[i]]=k;
}
}
bool cmp(Node x,Node y){
return x.h>y.h;
}
void unite(int x,int y){
fa[x]=y;
sz[y]+=sz[x];
mn[y]=min(mn[y],mn[x]);
mx[y]=max(mx[y],mx[x]);
}
int main(){
scanf("%d",&n);
scanf("%s",s);
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
get_sa(n+1);
get_height(n+1);
for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1,mx[rk[i-1]]=mn[rk[i-1]]=val[i];
for(int i=1;i<n;i++)g[i].h=h[i+1],g[i].x=i+1,g[i].y=i;
sort(g+1,g+n,cmp);
memset(sum,128,sizeof(sum));
for(int i=g[1].h,j=1;i>=0;i--){
ans[i]=ans[i+1],sum[i]=sum[i+1];
for(;j<n&&g[j].h==i;j++){
int x=find(g[j].x),y=find(g[j].y);
sum[i]=max(sum[i],1ll*mx[x]*mx[y]);
sum[i]=max(sum[i],1ll*mn[x]*mn[y]);
ans[i]+=1ll*sz[x]*sz[y];
unite(x,y);
}
}
for(int i=0;i<n;i++)printf("%lld %lld\n",ans[i],ans[i]==0?0:sum[i]);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: