洛谷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 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9648945.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值