廣義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 }