【CF666E】Forensic Examination - 廣義後綴自動機+線段樹合併

廣義SAM專題的最後一題了……呼node

題意:

給出一個長度爲$n$的串$S$和$m$個串$T_{1\cdots m}$,給出$q$個詢問$l,r,pl,pr$,詢問$S[pl\cdots pr]$在$T_l\cdots T_r$中哪一個串出現次數最多,出現了多少次。ios

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

串中只會出現小寫字母code

題解:

神題啊……放圖鎮樓blog

先對T串建出廣義SAM,而後把S放到上面匹配,求出每一個字符所表明的節點,那麼每次查詢就至關於求這一段字符在SAM上對應的節點的right集合包含的字符串的衆數是哪一個串,顯然這是parent樹上的一個子樹衆數問題;排序

考慮如何維護right集合在全部$T$中的出現次數,能夠對每個節點開一棵線段樹,維護每一個T串的出現次數的最大值,這樣子在parent樹上從下往上線段樹合併便可求出right集合;字符串

把詢問離線按照右端點排序,把詢問標記打在parent樹上,最後dfs一遍合併+處理詢問便可;string

口胡起來不難可是寫起來……超爽!it

代碼:

 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 }
相關文章
相關標籤/搜索