[cf587F]Duff is Mad

先建出AC自动机,即求其fail树上,$s_{l},s_{l+1},...,s_{r}$这些串的位置的子树中有多少个$k$的前缀

对$[l,r]$区间分块(设块大小为$k$),询问分为块内和块外两部分:

对于块内,直接统计每一个块对每一个$s_{k}$的答案,枚举每一个块,问题可以看作对于每一个$k$的前缀求其到根路径上有多少个串,dfs一下即可处理(一起dfs求出所有位置的答案,再枚举$s_{k}$),时间复杂度为$o(\frac{n^{2}}{k})$

对于块外,先枚举$s_{k}$,然后单点修改+子树查询,线段树维护即可,时间复杂度为$o(nk\log_{2}n)$

取$k=\sqrt{\frac{n}{\log_{2}n}}$最优,时间复杂度为$o(n\sqrt{n\log_{2}n})$

(好像也可以直接数链剖分+可持久化线段树来做,复杂度为两个log)

[cf587F]Duff is Mad
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define K 200
  5 #define NK 505
  6 #define ll long long
  7 #define L (k<<1)
  8 #define R (L+1)
  9 #define mid (l+r>>1)
 10 struct ji{
 11     int nex,to;
 12 }edge[N];
 13 struct qu{
 14     int l,r,id;
 15 };
 16 queue<int>q;
 17 vector<int>pos[N];
 18 vector<qu>v[N];
 19 int V,E,n,m,l,r,k,len[N],nex[N],ch[N][26],head[N],dfn[N],sz[N],sum[N],st[NK],ed[NK],bl[N],g[NK][N],f[N<<2];
 20 char s[N];
 21 ll ans[N];
 22 void add(int x,int y){
 23     edge[E].nex=head[x];
 24     edge[E].to=y;
 25     head[x]=E++;
 26 }
 27 void build(){
 28     for(int i=0;i<26;i++)
 29         if (ch[1][i]){
 30             nex[ch[1][i]]=1;
 31             q.push(ch[1][i]);
 32         }
 33     while (!q.empty()){
 34         int k=q.front();
 35         q.pop();
 36         add(nex[k],k);
 37         for(int i=0;i<26;i++)
 38             if (ch[k][i]){
 39                 int ans=nex[k];
 40                 while ((ans>1)&&(!ch[ans][i]))ans=nex[ans];
 41                 if (!ch[ans][i])nex[ch[k][i]]=ans;
 42                 else nex[ch[k][i]]=ch[ans][i];
 43                 q.push(ch[k][i]);
 44             }
 45     }
 46 }
 47 void dfs(int k){
 48     sz[k]=1;
 49     dfn[k]=++l;
 50     for(int i=head[k];i!=-1;i=edge[i].nex){
 51         dfs(edge[i].to);
 52         sz[k]+=sz[edge[i].to];
 53     }
 54 }
 55 void tot(int k){
 56     for(int i=head[k];i!=-1;i=edge[i].nex){
 57         sum[edge[i].to]+=sum[k];
 58         tot(edge[i].to);
 59     }
 60 }
 61 void update(int k,int l,int r,int x,int y){
 62     f[k]+=y;
 63     if (l==r)return;
 64     if (x<=mid)update(L,l,mid,x,y);
 65     else update(R,mid+1,r,x,y);
 66 }
 67 int query(int k,int l,int r,int x,int y){
 68     if ((l>y)||(x>r))return 0;
 69     if ((x<=l)&&(r<=y))return f[k];
 70     return query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
 71 }
 72 int main(){
 73     scanf("%d%d",&n,&m);
 74     V=1;
 75     for(int i=1;i<=n;i++){
 76         scanf("%s",s);
 77         len[i]=strlen(s);
 78         for(int j=0,k=1;s[j];j++){
 79             if (!ch[k][s[j]-'a'])ch[k][s[j]-'a']=++V;
 80             k=ch[k][s[j]-'a'];
 81             pos[i].push_back(k);
 82         }
 83     }
 84     memset(head,-1,sizeof(head));
 85     build();
 86     for(int i=1;i<=n;i++){
 87         bl[i]=(i-1)/K+1;
 88         if (!st[bl[i]])st[bl[i]]=i;
 89         ed[bl[i]]=i;
 90     }
 91     dfs(1);
 92     for(int i=1;i<=bl[n];i++){
 93         memset(sum,0,sizeof(sum));
 94         for(int j=st[i];j<=ed[i];j++)sum[pos[j][len[j]-1]]++;
 95         tot(1);
 96         for(int j=1;j<=n;j++)
 97             for(int k=0;k<len[j];k++)g[i][j]+=sum[pos[j][k]];
 98     }
 99     for(int i=1;i<=m;i++){
100         scanf("%d%d%d",&l,&r,&k);
101         if (bl[l]==bl[r])v[k].push_back(qu{l,r,i});
102         else{
103             v[k].push_back(qu{l,ed[bl[l]],i});
104             v[k].push_back(qu{st[bl[r]],r,i});
105             for(int j=bl[l]+1;j<bl[r];j++)ans[i]+=g[j][k];
106         }
107     }
108     for(int i=1;i<=n;i++){
109         for(int j=0;j<len[i];j++)update(1,1,V,dfn[pos[i][j]],1);
110         for(int j=0;j<v[i].size();j++)
111             for(int k=v[i][j].l;k<=v[i][j].r;k++){
112                 int kk=pos[k][len[k]-1];
113                 ans[v[i][j].id]+=query(1,1,V,dfn[kk],dfn[kk]+sz[kk]-1);
114             }
115         for(int j=0;j<len[i];j++)update(1,1,V,dfn[pos[i][j]],-1);
116     }
117     for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
118 }
View Code

 

上一篇:CF587F. Duff is Mad


下一篇:CF587F Duff is Mad