[NOI2015][BZOJ4199] 品酒大会|后缀数组|并查集

八中并没有题面……

 

后缀数组

即lcp(i,j)=l的后缀对的数量及w[i]*w[j]的最大值。

按height从大到小处理,把相邻的合并到一起,并查集维护。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #define inf 1ll<<62
  8 #define ll long long
  9 #define N 300005
 10 using namespace std;
 11 char s[N];
 12 int len,w[N];
 13 int fa[N],size[N],list[N],max_val[N],min_val[N];
 14 int sa[N],rank[N],height[N],t1[N],t2[N],cc[N];
 15 ll ans[2][N];
 16 inline int read()
 17 {
 18     int a=0,f=1; char c=getchar();
 19     while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
 20     while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
 21     return a*f;
 22 }
 23 inline bool cmp(int x,int y)
 24 {
 25     return height[x]==height[y]?x>y:height[x]>height[y];
 26 }
 27 inline bool cmp0(int *y,int a,int b,int k)
 28 {
 29     int arank1=y[a];
 30     int brank1=y[b];
 31     int arank2=a+k>=len?-1:y[a+k];
 32     int brank2=b+k>=len?-1:y[b+k];
 33     return arank1==brank1&&arank2==brank2;
 34 }
 35 inline void make_sa()
 36 {
 37     int m=256;
 38     int *x=t1,*y=t2;
 39     for (int i=0;i<m;i++) cc[i]=0;
 40     for (int i=0;i<len;i++) ++cc[x[i]=s[i]];
 41     for (int i=1;i<m;i++) cc[i]+=cc[i-1];
 42     for (int i=len-1;i>=0;i--) sa[--cc[x[i]]]=i;
 43     for (int k=1;k<len;k<<=1)
 44     {
 45         int p=0;
 46         for (int i=len-k;i<len;i++) y[p++]=i;
 47         for (int i=0;i<len;i++)
 48             if (sa[i]>=k) y[p++]=sa[i]-k;
 49         for (int i=0;i<m;i++) cc[i]=0;
 50         for (int i=0;i<len;i++) ++cc[x[y[i]]];
 51         for (int i=1;i<m;i++) cc[i]+=cc[i-1];
 52         for (int i=len-1;i>=0;i--) sa[--cc[x[y[i]]]]=y[i];
 53         swap(x,y);
 54         m=1; x[sa[0]]=0;
 55         for (int i=1;i<len;i++)
 56             x[sa[i]]=cmp0(y,sa[i-1],sa[i],k)?m-1:m++;
 57         if (m>=len) break;
 58     }
 59 }
 60 inline void make_height()
 61 {
 62     for (int i=0;i<len;i++) rank[sa[i]]=i;
 63     int k=0; height[0]=0;
 64     for (int i=0;i<len;i++)
 65     {
 66         if (!rank[i]) continue;
 67         int j=sa[rank[i]-1];
 68         if (k) k--;
 69         while (s[i+k]==s[j+k]) k++;
 70         height[rank[i]]=k;
 71     }
 72 }
 73 int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
 74  
 75 inline void merge(int x,int y)
 76 {
 77     size[y]+=size[x];
 78     max_val[y]=max(max_val[y],max_val[x]);
 79     min_val[y]=min(min_val[y],min_val[x]);
 80     fa[x]=y;
 81 }
 82 int main()
 83 {
 84     len=read(); 
 85     scanf("%s",s);
 86     for (int i=0;i<len;i++) w[i]=read();
 87     make_sa();
 88     make_height();
 89     for (int i=0;i<len;i++)
 90     {
 91         max_val[i]=min_val[i]=w[sa[i]];
 92         fa[i]=i;
 93         size[i]=1;
 94         list[i]=i;
 95         ans[1][i]=-inf;
 96     }
 97     sort(list,list+len,cmp);
 98    
 99     for (int i=0;i<len-1;i++)
100     {
101         int x=find(list[i]-1),y=find(list[i]);
102         ans[0][height[list[i]]]+=1ll*size[x]*size[y];
103         ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*max_val[x]*max_val[y]);
104         ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*max_val[x]*min_val[y]);
105         ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*min_val[x]*max_val[y]);
106         ans[1][height[list[i]]]=max(ans[1][height[list[i]]],1ll*min_val[x]*min_val[y]);
107         merge(x,y);
108     }
109     for (int i=len-2;i>=0;i--) ans[0][i]+=ans[0][i+1],ans[1][i]=max(ans[1][i],ans[1][i+1]);
110     for (int i=0;i<len;i++) printf("%lld %lld\n",ans[0][i],ans[0][i]?ans[1][i]:0);
111     return 0;
112 }

 

posted @ 2015-08-22 22:01  ws_fqk  阅读(294)  评论(0编辑  收藏  举报