bzoj1921 CTSC2010 jewelry

    xiaoxiao2021-12-14  20

    大概是四节课写代码,三节课debug,七个长相差不多的dfs穿插其中…… 好了不吐槽了; 题意: 给定一棵点上有字母的树,和一个母串 求树上点两两之间 N2 条路径在母串中匹配次数和

    这里采用的基本是《CTSC2010珠宝商新解》–许昊然的做法 首先考虑两种不同的暴力: 1.枚举端点dfs,SAM上跑转移 O(N2) 2.这个暴力比较特殊; 考虑一个作为路径lca的点A,则我们可以尝试用A子树中两条“半路径”拼出原路径; 不妨设A上字母为 i ,则需 (x,i) , (i,y) 构成(x,y); 这个问题可以通过在正反串的后缀树上打标记,再下放至叶子就可以合并了; 单次O(N),总的 O(N2)

    那么正解肯定是把他们拼起来啦; 解法1喜欢n较小的情况(当然soas解法2); 解法2单次复杂度与子树大小无关的; 借助点分治这个平台,二者便可巧妙结合:

    在点分治中,如果子树大小小于 N 便采用解法1,并停止递归; 如果子树大小大于 N 便采用解法2;

    其中由于第一步子树之间相互独立,则最差 NN 第二步可以证明大小大于 N 的分治子树不超过 N 个,故也是 NN

    但参拜lct1999的题解得知论文有一个细节处理不当 即在分治去重中也是应该依据子树大小判断解法的

    嗯…后缀树怎么求? 一般的字符集小的前提下:SAM–>后缀树–>SA

    附上写过最丑的代码…..

    #include<bits/stdc++.h> #define rep(i,k,n) for(int i=k;i<=n;i++) #define rep2(i,k,n) for(int i=k;i>=n;i--) #define pa pair<int,int> #define mk make_pair #define fr first #define sc second using namespace std; typedef long long ll; const int N=1e5+7; const int inf=0x3f3f3f3f; struct tu{ struct E{ int to,next;E(int to=0,int next=0):to(to),next(next){} }edge[N<<1]; int head[N],tot; void init(){tot=0;} void add(int x,int y){ edge[++tot]=E(y,head[x]);head[x]=tot; } }T; int n,m; struct machine{ tu tree; int tot,fa[N],ch[N][26],len[N],val[N],nod[N],p,last,sz[N],a[N],c[N],rk[N],q[N],mx[N]; char s[N]; void init(){last=p=tot=0;} void extend(int c,int pos){ int x; p=last,last=x=++tot; len[x]=len[p]+1; nod[x]=sz[x]=1; mx[x]=pos; for(;!ch[p][c];p=fa[p])ch[p][c]=x; if(ch[p][c]!=x){ int q=ch[p][c]; if(len[p]+1==len[q]){ fa[x]=q; }else{ int nq=++tot; len[nq]=len[p]+1; fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[q]=fa[x]=nq; for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq; } } } void build(){ rep(i,1,m)extend(s[i]-'a',i); } void build_tree(){ tree.init(); rep(i,1,tot)tree.add(fa[i],i); memset(c,0,sizeof(c)); rep(i,1,tot)c[len[i]]++; rep(i,1,tot)c[i]+=c[i-1]; rep(i,1,tot)rk[i]=c[len[i]]--; rep(i,1,tot)q[rk[i]]=i; rep2(i,tot,1) sz[fa[q[i]]]+=sz[q[i]],mx[fa[q[i]]]=max(mx[fa[q[i]]],mx[q[i]]); } pa trans(pa x,char c){ int pos=x.fr; int now=x.sc; int l=mx[pos]-len[pos]+1; int r=mx[pos]-len[fa[pos]]; int who=r-now; if(who>=l && pos){ if(s[who]==c)return mk(pos,now+1); else return mk(-1,-1); }else{ for(int i=tree.head[pos];i;i=tree.edge[i].next){ int v=tree.edge[i].to; r=mx[v]-len[fa[v]]; if(s[r]==c)return mk(v,1); } return mk(-1,-1); } } void mem(){memset(val,0,sizeof(val));} void push_down(){ rep(i,1,tot) for(int j=tree.head[q[i]];j;j=tree.edge[j].next){ int v=tree.edge[j].to; val[v]+=val[q[i]]; } memset(a,0,sizeof(a)); rep(i,1,tot)if(nod[i])a[len[i]]=val[i]; } }t1,t2; int sz[N],mx[N],vis[N],root,S,Q,fa[N]; ll Ans=0,tmp; char V[N]; void getrt(int x,int f){ sz[x]=1,mx[x]=0; for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(!vis[v] && v!=f){ getrt(v,x); mx[x]=max(mx[x],sz[v]); sz[x]+=sz[v]; } }mx[x]=max(mx[x],S-sz[x]); if(mx[x]<mx[root])root=x; } void dfs3_1(int x,int f,pa now){ now=t1.trans(now,V[x]); if(now.fr==-1)return; t1.val[now.fr]++; for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v])dfs3_1(v,x,now); } } void dfs3_2(int x,int f,pa now){ now=t2.trans(now,V[x]); if(now.fr==-1)return; t2.val[now.fr]++; for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v])dfs3_2(v,x,now); } } ll sol1(int x,int f,pa now1,pa now2){ t1.mem();t2.mem(); if(now1.fr==-1 || now2.fr==-1)return 0; dfs3_1(x,f,now1); dfs3_2(x,f,now2); t1.push_down();t2.push_down(); ll ans=0; rep(i,1,m)ans+=1ll*t1.a[i]*t2.a[m-i+1]; return ans; } void dfs5(int x,int f,int an,int now,int ok){ now=t1.ch[now][V[x]-'a']; if(!now)return; if(x==an){ now=t1.ch[now][V[fa[x]]-'a']; if(!now)return; now=t1.ch[now][V[x]-'a']; if(!now)return; ok=1; f=0; } if(!ok)dfs5(fa[x],x,an,now,ok); else{ tmp+=t1.sz[now]; for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v] && v!=fa[x])dfs5(v,x,an,now,ok); } } } void dfs4(int x,int f,int an){ dfs5(x,0,an,0,0); for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v])dfs4(v,x,an); } } ll sol2(int x,int f){ tmp=0; dfs4(x,f,x); return tmp; } void way1(int x){ Ans+=sol1(x,0,mk(0,0),mk(0,0)); for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(!vis[v]){ if(sz[v]>Q){ Ans-=sol1(v,x,t1.trans(mk(0,0),V[x]),t2.trans(mk(0,0),V[x])); }else{ Ans-=sol2(v,x); } } } } void dfs2(int x,int f,int now){ now=t1.ch[now][V[x]-'a']; if(!now)return; tmp+=t1.sz[now]; for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v])dfs2(v,x,now); } } void dfs(int x,int f){ dfs2(x,0,0); for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v])dfs(v,x); } } void way2(int x){ tmp=0; dfs(x,0); } void Dfs(int x,int f){ fa[x]=f; sz[x]=1; for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(v!=f && !vis[v]){ Dfs(v,x); sz[x]+=sz[v]; } } } void go(int x){ if(sz[x]<=Q){way2(x);Ans+=tmp;} else { vis[x]=1; Dfs(x,0); way1(x); for(int i=T.head[x];i;i=T.edge[i].next){ int v=T.edge[i].to; if(!vis[v]){ S=sz[v],root=0,getrt(v,x); go(root); } } } } void solve(){ mx[0]=inf; S=n,root=0,getrt(1,0); go(root); } int main(){ scanf("%d%d",&n,&m); Q=sqrt(n)+1; int x,y;T.init(); rep(i,1,n-1){ scanf("%d%d",&x,&y); T.add(x,y); T.add(y,x); }scanf("%s%s",V+1,t1.s+1); t1.init();t2.init(); memcpy(t2.s,t1.s,sizeof(t1.s)); rep(i,1,m>>1)swap(t2.s[i],t2.s[m-i+1]); t1.build(); t2.build(); t1.build_tree(); t2.build_tree(); solve(); printf("%lld\n",Ans); }
    转载请注明原文地址: https://ju.6miu.com/read-972325.html

    最新回复(0)