luogu4770 [NOI2018]你的名字 (SAM+主席樹)
阿新 • • 發佈:2019-01-01
對S建SAM,拿著T在上面跑
跑的時候不僅無法轉移要跳parent,轉移過去不在範圍內也要跳parent(注意因為範圍和長度有關,跳的時候應該把長度一點一點地縮)
這樣就能得到對於T的每個字首,它最長的不合法的字尾的長度ill[i]
得到他要去重,以後可以再對T建SAM,然後對於每個節點,$ans+=max(0,len[i]-max(len[fa[i]],ill[pos[i]]))$,其中pos[i]是它的right集合中隨便一個位置(因為每個位置的小於len的ill都一樣)
那麼怎麼判在不在範圍內呢..似乎可以線段樹合併,帶個log地求出每個節點的right
當然也可以直接dfs序然後建主席樹
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 #define MP make_pair 5 using namespace std; 6 typedef long long ll; 7 const int maxn=1e6+10; 8 9 inline char gc(){ 10 return getchar(); 11 static constint maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf; 12 return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++; 13 } 14 inline ll rd(){ 15 ll x=0;char c=gc();bool neg=0; 16 while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();} 17 while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc(); 18 return neg?(~x+1):x; 19 } 20 21 struct SAM{ 22 int len[maxn*2],fa[maxn*2],tr[maxn*2][26],pct,lst,pos[maxn*2]; 23 24 inline void clear(){ 25 while(pct){ 26 CLR(tr[pct],0); 27 len[pct]=fa[pct]=pos[pct]=0; 28 pct--; 29 }pct=lst=1; 30 } 31 32 inline void insert(int x,bool b){ 33 int p=++pct; 34 len[p]=len[lst]+1;pos[p]=len[p]; 35 int o=lst;lst=p; 36 for(;o&&!tr[o][x];o=fa[o]) tr[o][x]=p; 37 if(!o){fa[p]=1;return;} 38 int q=tr[o][x]; 39 if(len[q]==len[o]+1){fa[p]=q;return;} 40 int qq=++pct;if(b) pos[qq]=pos[p]; 41 len[qq]=len[o]+1;fa[qq]=fa[q]; 42 memcpy(tr[qq],tr[q],sizeof(tr[q])); 43 fa[q]=fa[p]=qq; 44 for(;o&&tr[o][x]==q;o=fa[o]) tr[o][x]=qq; 45 } 46 }S,T; 47 48 char s[maxn]; 49 int N,M,Q; 50 int ill[maxn]; 51 int cnt[maxn],rnk[maxn],dfn[maxn][2],id[maxn],tot; 52 vector<int> eg[maxn]; 53 54 inline void dfs(int x){ 55 id[++tot]=x;dfn[x][0]=tot; 56 for(int i=0;i<eg[x].size();i++) dfs(eg[x][i]); 57 dfn[x][1]=tot; 58 } 59 60 int rt[maxn],num[maxn*20],ch[maxn*20][2],pct; 61 62 inline void insert(int pre,int &p,int l,int r,int x,int y){ 63 p=++pct;num[p]=num[pre]+y; 64 if(l<r){ 65 int m=l+r>>1; 66 if(x<=m) insert(ch[pre][0],ch[p][0],l,m,x,y),ch[p][1]=ch[pre][1]; 67 else insert(ch[pre][1],ch[p][1],m+1,r,x,y),ch[p][0]=ch[pre][0]; 68 } 69 } 70 71 inline int query(int pre,int p,int l,int r,int x,int y){ 72 if(x>y) return 0; 73 if(x<=l&&r<=y) return num[p]-num[pre]; 74 int m=l+r>>1,re=0; 75 if(x<=m) re=query(ch[pre][0],ch[p][0],l,m,x,y); 76 if(y>=m+1) re+=query(ch[pre][1],ch[p][1],m+1,r,x,y); 77 return re; 78 } 79 80 int main(){ 81 //freopen("","r",stdin); 82 int i,j,k; 83 scanf("%s",s+1);N=strlen(s+1); 84 S.clear(); 85 for(i=1;i<=N;i++) S.insert(s[i]-'a',0); 86 87 for(i=2;i<=S.pct;i++) eg[S.fa[i]].push_back(i); 88 dfs(1); 89 for(i=1;i<=tot;i++){ 90 if(S.pos[id[i]]) insert(rt[i-1],rt[i],1,N,S.pos[id[i]],1); 91 else rt[i]=rt[i-1]; 92 } 93 94 Q=rd(); 95 for(i=1;i<=Q;i++){ 96 scanf("%s",s+1);M=strlen(s+1); 97 int l=rd(),r=rd(); 98 int now=1,nl=0; 99 for(j=1;j<=M;j++){ 100 int x=s[j]-'a'; 101 while(now&&!(S.tr[now][x]&&query(rt[dfn[S.tr[now][x]][0]-1],rt[dfn[S.tr[now][x]][1]],1,N,l+nl,r))){ 102 if(!nl){now=0;break;} 103 nl--; 104 if(nl==S.len[S.fa[now]]) now=S.fa[now]; 105 } 106 if(now) nl++,now=S.tr[now][x]; 107 else now=1; 108 ill[j]=nl; 109 // printf("~%d %d\n",j,ill[j]); 110 } 111 T.clear(); 112 for(j=1;j<=M;j++) T.insert(s[j]-'a',1); 113 ll ans=0; 114 for(j=2;j<=T.pct;j++){ 115 ans+=max(0,T.len[j]-max(T.len[T.fa[j]],ill[T.pos[j]])); 116 } 117 printf("%lld\n",ans); 118 } 119 return 0; 120 }