【CF666E】Forensic Examination - 广义后缀自动机+线段树合并

广义SAM专题的最后一题了……呼

题意:

给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_l\cdots T_r$中哪个串出现次数最多,出现了多少次。

$1\leq n,q\leq 10^5,1\leq m,\sum|T|\leq 10^4$

串中只会出现小写字母

题解:

神题啊……放图镇楼

先对T串建出广义SAM,然后把S放到上面匹配,求出每个字符所代表的节点,那么每次查询就相当于求这一段字符在SAM上对应的节点的right集合包含的字符串的众数是哪个串,显然这是parent树上的一个子树众数问题;

考虑如何维护right集合在所有$T$中的出现次数,可以对每一个节点开一棵线段树,维护每个T串的出现次数的最大值,这样子在parent树上从下往上线段树合并即可求出right集合;

把询问离线按照右端点排序,把询问标记打在parent树上,最后dfs一遍合并+处理询问即可;

口胡起来不难但是写起来……超爽!

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<cmath>
  7 #include<queue>
  8 #define inf 2147483647
  9 #define eps 1e-9
 10 using namespace std;
 11 typedef long long ll;
 12 typedef double db;
 13 struct task{
 14     int v,id;
 15     task(){v=id=0;}
 16     friend bool operator <(task a,task b){
 17         return a.v==b.v?a.id>b.id:a.v<b.v;
 18     }
 19 }ans[500001];
 20 struct qu{
 21     int l,r,ql,qr;
 22 }q[500001];
 23 struct edge{
 24     int v,next;
 25 }a[1000001];
 26 struct node{
 27     int ls,rs;
 28     task v;
 29 }t[4000001];
 30 int n,m,Q,len,ch,nw=1,tote=0,tot=1,rt=1,cnt=0,last,head[1000001],rts[1000001],son[1000001][26],fa[1000001],mx[1000001],f[1000001][20];
 31 vector<int>qrs[500001];
 32 vector<int>as[500001];
 33 char st[500001],tt[500001];
 34 void add(int u,int v){
 35     a[++tote].v=v;
 36     a[tote].next=head[u];
 37     head[u]=tote;
 38 }
 39 void updata(int &u,int l,int r,int x){
 40     if(!u)u=++cnt;
 41     if(l==r){
 42         t[u].v.v++;
 43         t[u].v.id=x;
 44         return;
 45     }
 46     int mid=(l+r)/2;
 47     if(x<=mid)updata(t[u].ls,l,mid,x);
 48     else updata(t[u].rs,mid+1,r,x);
 49     t[u].v=max(t[t[u].ls].v,t[t[u].rs].v);
 50 }
 51 void merge(int &x,int y){
 52     if(!x||!y){
 53         x|=y;
 54         return;
 55     }
 56     if(!t[x].ls&&!t[x].rs){
 57         t[x].v.v+=t[y].v.v;
 58         return;
 59     }
 60     merge(t[x].ls,t[y].ls);
 61     merge(t[x].rs,t[y].rs);
 62     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
 63 }
 64 task query(int u,int l,int r,int L,int R){
 65     if(L<=l&&r<=R){
 66         return t[u].v;
 67     }
 68     int mid=(l+r)/2;
 69     task ret;
 70     if(L<=mid)ret=max(ret,query(t[u].ls,l,mid,L,R));
 71     if(mid<R)ret=max(ret,query(t[u].rs,mid+1,r,L,R));
 72     return ret;
 73 }
 74 void extend(int ch){
 75     int p=last,np=++tot;
 76     mx[np]=mx[p]+1;
 77     for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
 78     if(!p)fa[np]=rt;
 79     else{
 80         int q=son[p][ch];
 81         if(mx[q]==mx[p]+1)fa[np]=q;
 82         else{
 83             int nq=++tot;
 84             mx[nq]=mx[p]+1;
 85             memcpy(son[nq],son[q],sizeof(son[q]));
 86             fa[nq]=fa[q];
 87             fa[q]=fa[np]=nq;
 88             for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq;
 89         }
 90     }
 91     last=np;
 92 }
 93 void dfs(int u){
 94     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
 95         int v=a[tmp].v;
 96         dfs(v);
 97         merge(rts[u],rts[v]);
 98     }
 99     for(int i=0,ii=as[u].size();i<ii;i++){
100         ans[as[u][i]]=query(rts[u],1,m,q[as[u][i]].l,q[as[u][i]].r);
101     }
102 }
103 int main(){
104     memset(head,-1,sizeof(head));
105     scanf("%s%d",st+1,&m);
106     n=strlen(st+1);
107     for(int i=1;i<=m;i++){
108         scanf("%s",tt);
109         len=strlen(tt);
110         last=rt;
111         for(int j=0;j<len;j++){
112             extend(tt[j]-'a');
113             updata(rts[last],1,m,i);
114         }
115     }
116     scanf("%d",&Q);
117     for(int i=1;i<=Q;i++){
118         scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].ql,&q[i].qr);
119         qrs[q[i].qr].push_back(i);
120     }
121     for(int i=2;i<=tot;i++){
122         f[i][0]=fa[i];
123         add(fa[i],i);
124     }
125     for(int j=1;j<=19;j++){
126         for(int i=1;i<=tot;i++){
127             f[i][j]=f[f[i][j-1]][j-1];
128         }
129     }
130     len=0;
131     for(int i=1;i<=n;i++){
132         ch=st[i]-'a';
133         for(;nw&&!son[nw][ch];)nw=fa[nw],len=mx[nw];
134         if(!nw){
135             nw=rt;
136             len=0;
137         }else{
138             nw=son[nw][ch];
139             len++;
140             for(int j=0,jj=qrs[i].size();j<jj;j++){
141                 int v=qrs[i][j];
142                 if(len>=q[v].qr-q[v].ql+1){
143                     int _nw=nw;
144                     for(int k=19;k>=0;k--){
145                         if(mx[f[_nw][k]]>=q[v].qr-q[v].ql+1){
146                             _nw=f[_nw][k];
147                         }
148                     }
149                     as[_nw].push_back(v);
150                 }
151             }
152         }
153     }
154     dfs(1);
155     for(int i=1;i<=Q;i++){
156         if(!ans[i].v)ans[i].id=q[i].l;
157         printf("%d %d\n",ans[i].id,ans[i].v);
158     }
159     return 0;
160 }
posted @ 2018-12-22 11:26  DCDCBigBig  阅读(240)  评论(0编辑  收藏  举报