洛谷P4218 [CTSC2010]珠宝商(后缀自动机+点分治)
这题思路太清奇了……->题解
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #define ll long long 8 using namespace std; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getchar())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getchar());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 20 const int N=1e5+5; 21 char str[N],s[N]; 22 ll ans=0; 23 int ver[N],Next[N],head[N],tot=0; 24 int sqr,id1[N],id2[N]; 25 inline void add(int u,int v){ 26 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 27 } 28 int vis[N],rt,son[N],sz[N],size,n,m; 29 struct SAM{ 30 int rt,last,tot,ch[N][26],fa[N],l[N],cnt[N]; 31 int s[N],tag[N],son[N][26],le[N]; 32 SAM(){rt=last=tot=1;} 33 int ins(int c){ 34 int p=last,np=++tot;last=np,le[np]=l[np]=l[p]+1,cnt[np]=1; 35 for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; 36 if(!p) fa[np]=rt; 37 else{ 38 int q=ch[p][c]; 39 if(l[q]==l[p]+1) fa[np]=q; 40 else{ 41 int nq=++tot; 42 memcpy(ch[nq],ch[q],sizeof(ch[q])); 43 l[nq]=l[p]+1,le[nq]=le[q]; 44 fa[nq]=fa[q],fa[q]=fa[np]=nq; 45 for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 46 } 47 } 48 return last; 49 } 50 int a[N],c[N]; 51 void calc(){ 52 for(int i=1;i<=tot;++i) ++c[l[i]]; 53 for(int i=1;i<=tot;++i) c[i]+=c[i-1]; 54 for(int i=tot;i;--i) a[c[l[i]]--]=i; 55 for(int i=tot,p;i>=2;--i){ 56 p=a[i]; 57 cnt[fa[p]]+=cnt[p]; 58 son[fa[p]][s[le[p]-l[fa[p]]]]=p; 59 } 60 } 61 void mark(int u,int fa,int now,int len){ 62 if(!now) return; 63 if(len==l[now]) now=son[now][str[u]-'a']; 64 else if(s[le[now]-len]!=str[u]-'a') now=0; 65 if(!now) return; 66 ++tag[now]; 67 for(int i=head[u];i;i=Next[i]){ 68 int v=ver[i]; 69 if(v!=fa&&!vis[v]) mark(v,u,now,len+1); 70 } 71 } 72 inline void push(){for(int i=1;i<=tot;++i) tag[a[i]]+=tag[fa[a[i]]];} 73 }sam1,sam2; 74 void findrt(int u,int fa){ 75 sz[u]=1,son[u]=0; 76 for(int i=head[u];i;i=Next[i]){ 77 int v=ver[i]; 78 if(v!=fa&&!vis[v]) 79 findrt(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]); 80 } 81 cmax(son[u],size-sz[u]); 82 if(!rt||son[u]<son[rt]) rt=u; 83 } 84 int num=0,g[N]; 85 void get(int u,int fa){ 86 g[++num]=u; 87 for(int i=head[u];i;i=Next[i]){ 88 int v=ver[i]; 89 if(v!=fa&&!vis[v]) get(v,u); 90 } 91 } 92 void getsum(int u,int fa){ 93 ++size; 94 for(int i=head[u];i;i=Next[i]){ 95 int v=ver[i]; 96 if(v!=fa&&!vis[v]) getsum(v,u); 97 } 98 } 99 void dfs(int u,int fa,int now){ 100 now=sam1.ch[now][str[u]-'a']; 101 if(!now) return; 102 ans+=sam1.cnt[now]; 103 for(int i=head[u];i;i=Next[i]){ 104 int v=ver[i]; 105 if(v!=fa&&!vis[v]) dfs(v,u,now); 106 } 107 } 108 void work(int u,int fa,int op){ 109 for(int i=1;i<=sam1.tot;++i) sam1.tag[i]=0; 110 for(int i=1;i<=sam2.tot;++i) sam2.tag[i]=0; 111 int to=str[fa]-'a'; 112 if(fa) sam1.mark(u,fa,sam1.son[1][to],1),sam2.mark(u,fa,sam2.son[1][to],1); 113 else sam1.mark(u,fa,1,0),sam2.mark(u,fa,1,0); 114 sam1.push(),sam2.push(); 115 for(int i=1;i<=m;++i) ans+=1ll*op*sam1.tag[id1[i]]*sam2.tag[id2[m-i+1]]; 116 } 117 void solve(int u){ 118 if(size<=sqr){ 119 num=0,get(u,0); 120 for(int i=1;i<=num;++i) dfs(g[i],0,sam1.rt); 121 return; 122 } 123 vis[u]=1,work(u,0,1); 124 for(int i=head[u];i;i=Next[i]) 125 if(!vis[ver[i]]) work(ver[i],u,-1); 126 for(int i=head[u];i;i=Next[i]){ 127 int v=ver[i]; 128 if(vis[v]) continue; 129 size=0,getsum(v,u); 130 rt=0,findrt(v,u); 131 solve(rt); 132 } 133 } 134 int main(){ 135 // freopen("testdata.in","r",stdin); 136 n=read(),m=read(); 137 for(int i=1,u,v;i<n;++i) 138 u=read(),v=read(),add(u,v),add(v,u); 139 scanf("%s",str+1),scanf("%s",s+1); 140 for(int i=1;i<=m;++i) sam1.s[i]=s[i]-'a',id1[i]=sam1.ins(s[i]-'a'); 141 reverse(s+1,s+1+m); 142 for(int i=1;i<=m;++i) sam2.s[i]=s[i]-'a',id2[i]=sam2.ins(s[i]-'a'); 143 sam1.calc(),sam2.calc(); 144 rt=0,son[0]=n+1,size=n,sqr=sqrt(n); 145 findrt(1,0),solve(rt); 146 printf("%lld\n",ans); 147 return 0; 148 }
深深地明白自己的弱小