1. 程式人生 > >Codeforces 666E Forensic Examination SAM+權值線段樹

Codeforces 666E Forensic Examination SAM+權值線段樹

namespace return 匹配 roo tchar long bits codeforce XA

第一次做這種$SAM$帶權值線段樹合並的題 然而$zjq$神犇看完題一頓狂碼就做出來了 $Orz$

首先把所有串當成一個串建$SAM$ 我們對$SAM$上每個點 建一棵權值線段樹 每個葉子節點表示一個匹配串能到達這個點的子串個數 這樣我們對最後的$SAM$的權值線段樹按$parent$樹合並 詢問的時候找到對應的$SAM$上的權值線段樹直接查詢就好了

具體的操作看代碼吧~

#include<bits/stdc++.h>
using namespace std;
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pa pair<int,int> #define mod 1000000007 #define ll long long #define mk make_pair #define pb push_back #define fi first #define se second #define cl(x) memset(x,0,sizeof x) #ifdef Devil_Gary #define bug(x) cout<<(#x)<<" "<<(x)<<endl #define debug(...) fprintf(stderr, __VA_ARGS__)
#else #define bug(x) #define debug(...) #endif const int INF = 0x7fffffff; const int N=1230010; /* char *TT,*mo,but[(1<<15)+2]; #define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/ inline int read(){ int x=0,rev=0,ch=getchar(); while(ch<'0'
||ch>'9'){if(ch=='-')rev=1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return rev?-x:x; } pa operator * (const pa&A,const pa&B){return A.fi==B.fi?(A.se<B.se?A:B):(A.fi>B.fi?A:B);} pa operator + (const pa&A,const pa&B){return mk(A.fi+B.fi,A.se);} pa t[N*23]; char s[N]; int n,m,Q,c[N][27],par[N],len[N],fa[N][21],ls[N*23],rs[N*23],h[N],rt=1,sz=1,last=1,root[N],w[N],b[N],id; void extend(int x){ int np=++sz,p=last; len[np]=len[p]+1,last=np; for(;p&&!c[p][x];p=par[p]) c[p][x]=np; if(!p) par[np]=rt; else{ int q=c[p][x]; if(len[p]+1==len[q]) par[np]=q; else{ int nq=++sz; len[nq]=len[p]+1,par[nq]=par[q],par[q]=par[np]=nq; memcpy(c[nq],c[q],sizeof c[nq]); for(;p&&c[p][x]==q;p=par[p]) c[p][x]=nq; } } } void modify(int&pos,int l,int r,int x){ if(!pos) pos=++id; if(l==r){ t[pos].fi++,t[pos].se=l; // cout<<t[pos].fi<<" "<<t[pos].se<<endl; return; } int mid=l+r>>1; if(x<=mid) modify(ls[pos],l,mid,x); else modify(rs[pos],mid+1,r,x); t[pos]=t[ls[pos]]*t[rs[pos]]; } inline int merge(int x,int y,int l,int r) { if (!x||!y) return x|y; int z=++id; if (l==r) { t[z]=t[x]+t[y]; return z; } int mid=(l+r)>>1; ls[z]=merge(ls[x],ls[y],l,mid),rs[z]=merge(rs[x],rs[y],mid+1,r); t[z]=t[ls[z]]*t[rs[z]]; return z; } pa Query(int pos,int l,int r,int nl,int nr){ if(!pos) return mk(0,0); if(nl<=l&&r<=nr) return t[pos]; int mid=l+r>>1; if(nr<=mid) return Query(ls[pos],l,mid,nl,nr); else if(nl>mid) return Query(rs[pos],mid+1,r,nl,nr); else return Query(ls[pos],l,mid,nl,nr)*Query(rs[pos],mid+1,r,nl,nr); } void topsort(){ for(int i=1;i<=sz;i++) w[len[i]]++; for(int i=1;i<=sz;i++) w[i]+=w[i-1]; for(int i=1;i<=sz;i++) b[w[len[i]]--]=i; for(int i=sz;i;i--){ int j=b[i]; if(par[j]) root[par[j]]=merge(root[par[j]],root[j],1,n); } } void get_fa(){ for(int i=1;i<=sz;i++) fa[i][0]=par[i]; for(int i=1;i<=20;i++) for(int j=1;j<=sz;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; } int get(int l,int r){ int L=r-l+1,x=h[r]; for(int i=20;~i;i--) if(len[fa[x][i]]>=L) x=fa[x][i]; // -len[par[x]]-len[par[fa[x][i]]] return x; } int main(){ #ifdef Devil_Gary freopen("in.txt","r",stdin); #endif scanf("%s",s+1),m=strlen(s+1); for(int i=1;i<=m;i++) extend(s[i]-'a'),h[i]=last; n=read(); for(int i=1;i<=n;i++){ scanf("%s",s+1),m=strlen(s+1),extend(26); for(int j=1;j<=m;j++) extend(s[j]-'a'),modify(root[last],1,n,i); } // bug(sz); topsort(),get_fa(); for(Q=read();Q;Q--){ int l=read(),r=read(),pl=read(),pr=read(),x=get(pl,pr); pa ans=Query(root[x],1,n,l,r); if(!ans.fi) printf("%d 0\n",l); else printf("%d %d\n",ans.se,ans.fi); } }

Codeforces 666E Forensic Examination SAM+權值線段樹