BZOJ3277 串 【后缀数组】【二分答案】【主席树】

题目分析:

用"$"连接后缀数组,然后做一个主席树求区间内不同的数的个数。二分一个前缀长度再在主席树上求不同的数的个数。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxn = 132000;
  5 const int N = 130000;
  6 
  7 int m,n,k;
  8 string hmk[maxn],str;
  9 int sum[maxn];
 10 
 11 int sa[maxn],rk[maxn],X[maxn],Y[maxn];
 12 int height[maxn],h[maxn],RMQ[maxn][20],Tnum;
 13 long long ans[maxn];
 14 
 15 struct node{
 16     int ch[2],sum;
 17 }CMT[maxn*35];
 18 
 19 int chk(int x,int k){
 20     return rk[sa[x]]==rk[sa[x-1]]&&rk[sa[x]+(1<<k)]==rk[sa[x-1]+(1<<k)];
 21 }
 22 
 23 void getsa(){
 24     for(int i=0;i<n;i++) X[str[i]]++;
 25     for(int i=1;i<=N;i++) X[i] += X[i-1];
 26     for(int i=n-1;i>=0;i--) sa[X[str[i]]--] = i;
 27     for(int i = 2, num = 1;i <= n;i++)
 28     rk[sa[i]] = (str[sa[i]] == str[sa[i-1]]?num:++num);
 29     rk[sa[1]] = 1;
 30     for(int k=1;(1<<k-1)<=n;k++){
 31     for(int i=1;i<=N;i++) X[i] = 0;
 32     for(int i=n-(1<<k-1);i<n;i++) Y[i-n+(1<<k-1)+1]=i;
 33     for(int i=1,j=(1<<k-1)+1;i<=n;i++)
 34         if(sa[i]>=(1<<k-1))Y[j++]=sa[i]-(1<<k-1);
 35     for(int i=0;i<n;i++) X[rk[i]]++;
 36     for(int i=1;i<=N;i++) X[i]+=X[i-1];
 37     for(int i=n;i>=1;i--) sa[X[rk[Y[i]]]--] = Y[i];
 38     int num = 1; Y[sa[1]] = 1;
 39     for(int i=2;i<=n;i++) Y[sa[i]] = (chk(i,k-1)?num:++num);
 40     for(int i=0;i<n;i++) rk[i] = Y[i];
 41     if(num == n) break;
 42     }
 43 }
 44 void getheight(){
 45     for(int i=0;i<n;i++){
 46     if(i) h[i] = max(0,h[i-1]-1); else h[i] = 0;
 47     if(rk[i] == 1) continue;
 48     int comp = sa[rk[i]-1];
 49     while(str[comp+h[i]] == str[i+h[i]])h[i]++;
 50     }
 51     for(int i=0;i<n;i++) height[rk[i]] = h[i];
 52     for(int i=1;i<=n;i++) RMQ[i][0] = height[i];
 53     for(int k=1;(1<<k)<=n;k++){
 54     for(int i=1;i<=n;i++){
 55         if(i+(1<<k-1)>n) RMQ[i][k]=RMQ[i][k-1];
 56         else RMQ[i][k] = min(RMQ[i][k-1],RMQ[i+(1<<k-1)][k-1]);
 57     }
 58     }
 59 }
 60 
 61 int pww[maxn];
 62 int getLCP(int L,int R){
 63     if(L == R) return n-sa[L];
 64     L++;
 65     int k = pww[R-L+1];
 66     return min(RMQ[L][k],RMQ[R-(1<<k)+1][k]);
 67 }
 68 
 69 void build_empty_tree(int now,int tl,int tr){
 70     if(tl == tr) return;
 71     int mid = (tl+tr)/2;
 72     Tnum++; CMT[now].ch[0] = Tnum;
 73     build_empty_tree(Tnum,tl,mid);
 74     Tnum++; CMT[now].ch[1] = Tnum;
 75     build_empty_tree(Tnum,mid+1,tr);
 76 }
 77 
 78 void Modify(int lst,int now,int tl,int tr,int pos,int dt){
 79     CMT[now] = CMT[lst];
 80     if(tl == tr){CMT[now].sum += dt;}
 81     else{
 82     int mid = (tl+tr)/2;
 83     if(pos <= mid){
 84         CMT[now].ch[0] = ++Tnum;
 85         Modify(CMT[lst].ch[0],Tnum,tl,mid,pos,dt);
 86     }else{
 87         CMT[now].ch[1] = ++Tnum;
 88         Modify(CMT[lst].ch[1],Tnum,mid+1,tr,pos,dt);
 89     }
 90     CMT[now].sum += dt;
 91     }
 92 }
 93 
 94 int imp[maxn],his[maxn];
 95 void build_CMT(){
 96     his[0] = 1;
 97     for(int i=1;i<=n;i++){
 98     if(imp[sum[sa[i]]]){
 99         int z = ++Tnum;
100         Modify(his[i-1],z,1,n,imp[sum[sa[i]]],-1);
101         his[i] = ++Tnum; imp[sum[sa[i]]] = i;
102         Modify(z,his[i],1,n,i,1);
103     }else{
104         his[i] = ++Tnum; imp[sum[sa[i]]] = i;
105         Modify(his[i-1],his[i],1,n,i,1);
106     }
107     }
108 }
109 
110 int query(int now,int tl,int tr,int l,int r){
111     if(tl >= l && tr <= r) return CMT[now].sum;
112     if(tl > r || tr < l) return 0;
113     int mid = (tl+tr)/2;
114     int as=query(CMT[now].ch[0],tl,mid,l,r)+query(CMT[now].ch[1],mid+1,tr,l,r);
115     return as;
116 }
117 
118 int rgt[maxn];
119 void work(){
120     getsa();
121     getheight();
122     sum[n] = 1;rgt[n] = n;
123     for(int i=n-1;i>=0;i--){
124     sum[i] = sum[i+1]+(str[i] == '$');
125     if(str[i] == '$') rgt[i] = i;
126     else rgt[i] = rgt[i+1];
127     }
128     Tnum = 1;
129     build_empty_tree(1,1,n);
130     build_CMT();
131     for(int i=m;i<=n;i++){
132     int l = 0,r = rgt[sa[i]]-sa[i];
133     while(l < r){
134         int mid = (l+r+1)/2;
135         int al = 1,ar = i;
136         while(al < ar){
137         int midd = (al+ar)/2;
138         if(getLCP(midd,i) >= mid) ar = midd;
139         else al = midd+1;
140         }
141         int tl  = i,tr = n;
142         while(tl < tr){
143         int midd = (tl+tr+1)/2;
144         if(getLCP(i,midd) >= mid) tl = midd;
145         else tr = midd-1;
146         }
147         int mmp = query(his[tl],1,n,al,tl);
148         if(mmp >= k) l = mid;
149         else r = mid-1;
150     }
151     ans[m-sum[sa[i]]+1] += l;
152     }
153     for(int i=1;i<=m;i++) printf("%lld ",ans[i]);
154 }
155 
156 int main(){
157     ios::sync_with_stdio(false);
158     cin.tie(0);
159     cin >> m >> k;
160     for(int i=1;i<=m;i++) cin >> hmk[i];
161     for(int i=1;i<m;i++) str += hmk[i],str += '$';
162     str += hmk[m];
163     n = str.length();
164     pww[1] = 0;
165     for(int i=2;i<=n;i++) pww[i] = pww[i/2]+1;
166     work();
167     return 0;
168 }

 

posted @ 2018-12-11 14:38  menhera  阅读(225)  评论(0编辑  收藏  举报