zoukankan      html  css  js  c++  java
  • [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(nklog_{2}n)$

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

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

      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
    ",ans[i]);
    118 }
    View Code
  • 相关阅读:
    Linux自动批量增加公钥
    主机存活监控
    [Linux小技巧] 将 rm 命令删除的文件放在回收站
    Linux常见问题及命令
    数据分析职位招聘情况及发展前景分析
    SQL查询小案例
    Oracle查看表结构
    前端JSON请求转换Date问题
    Centos7最小化安装
    拓词和扇贝有何不同
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13967351.html
Copyright © 2011-2022 走看看