题意:有一棵树,树上每个结点上有一个字母,有两种操作:
1)询问树上两点u,v间有向路径上有多少个字母和某个固定的字符串相匹配
2)将结点u的字母修改为x
树剖+线段,暴力维护前缀和后缀哈希值(正反都要维护)以及区间内匹配的个数,合并两区间时判断一下跨过分界点的情况就行了。由于被匹配的字符串长度不超过100,所以最多只需维护长度为100的前缀/后缀。
但即使这样复杂度也足足有$O(100nlog^2n)$啊,这常数是得有多小才能过掉...
注意各种条件判断和细节处理,还有就是这题内存比较吃紧,使用动态开点可以节省一半的内存。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef unsigned long long ll; 4 const int N=1e5+10,M=19260817; 5 int hd[N],n,ne,m,Len,fa[N],son[N],siz[N],dep[N],top[N],dfn[N],rnk[N],tot,rt,ls[N<<1],rs[N<<1],tot2; 6 ll H,pm[N]; 7 char s1[N],s2[N]; 8 struct D { 9 int len,sum; 10 ll L[101],R[101]; 11 D(int ch=0) { 12 len=1; 13 sum=(Len==1&&ch==H); 14 L[1]=R[1]=ch; 15 } 16 } tr[N<<1][2]; 17 struct E {int v,nxt;} e[N<<1]; 18 D operator+(D a,D b) { 19 if(a.L[1]==0)return b; 20 if(b.L[1]==0)return a; 21 D c; 22 c.len=a.len+b.len; 23 c.sum=a.sum+b.sum; 24 for(int i=1; i<=min(100,c.len); ++i) { 25 if(i<=a.len)c.L[i]=a.L[i]; 26 else c.L[i]=a.L[a.len]*pm[i-a.len]+b.L[i-a.len]; 27 if(i<=b.len)c.R[i]=b.R[i]; 28 else c.R[i]=a.R[i-b.len]*pm[b.len]+b.R[b.len]; 29 } 30 for(int i=max(1,Len-b.len); i<=a.len&&i<=Len-1; ++i)if(a.R[i]*pm[Len-i]+b.L[Len-i]==H)c.sum++; 31 return c; 32 } 33 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 34 void dfs1(int u,int f,int d) { 35 fa[u]=f,son[u]=0,siz[u]=1,dep[u]=d; 36 for(int i=hd[u]; ~i; i=e[i].nxt) { 37 int v=e[i].v; 38 if(v==fa[u])continue; 39 dfs1(v,u,d+1),siz[u]+=siz[v]; 40 if(siz[v]>siz[son[u]])son[u]=v; 41 } 42 } 43 void dfs2(int u,int tp) { 44 top[u]=tp,dfn[u]=++tot,rnk[dfn[u]]=u; 45 if(son[u])dfs2(son[u],top[u]); 46 for(int i=hd[u]; ~i; i=e[i].nxt) { 47 int v=e[i].v; 48 if(v==fa[u]||v==son[u])continue; 49 dfs2(v,v); 50 } 51 } 52 #define mid ((l+r)>>1) 53 void pu(int u) { 54 tr[u][0]=tr[ls[u]][0]+tr[rs[u]][0]; 55 tr[u][1]=tr[rs[u]][1]+tr[ls[u]][1]; 56 } 57 void upd(int p,int x,int& u=rt,int l=1,int r=tot) { 58 if(l==r) {tr[u][0]=tr[u][1]=D(x); return;} 59 p<=mid?upd(p,x,ls[u],l,mid):upd(p,x,rs[u],mid+1,r); 60 pu(u); 61 } 62 void build(int& u=rt,int l=1,int r=tot) { 63 u=++tot2; 64 if(l==r) {tr[u][0]=tr[u][1]=D(s2[rnk[l]-1]); return;} 65 build(ls[u],l,mid),build(rs[u],mid+1,r),pu(u); 66 } 67 D qry(int L,int R,int f,int u=rt,int l=1,int r=tot) { 68 if(l>=L&&r<=R)return tr[u][f]; 69 if(l>R||r<L)return D(0); 70 if(f==0)return qry(L,R,f,ls[u],l,mid)+qry(L,R,f,rs[u],mid+1,r); 71 else return qry(L,R,f,rs[u],mid+1,r)+qry(L,R,f,ls[u],l,mid); 72 } 73 int qry2(int u,int v) { 74 D L=D(0),R=D(0),M; 75 for(; top[u]!=top[v];) { 76 if(dep[top[u]]>dep[top[v]])L=L+qry(dfn[top[u]],dfn[u],1),u=fa[top[u]]; 77 else R=qry(dfn[top[v]],dfn[v],0)+R,v=fa[top[v]]; 78 } 79 if(dep[u]>dep[v])M=qry(dfn[v],dfn[u],1); 80 else M=qry(dfn[u],dfn[v],0); 81 return (L+M+R).sum; 82 } 83 int main() { 84 pm[0]=1; 85 for(int i=1; i<N; ++i)pm[i]=pm[i-1]*M; 86 memset(hd,-1,sizeof hd),ne=0; 87 scanf("%d%d",&n,&m); 88 scanf("%s%s",s1,s2),Len=strlen(s1); 89 H=0; 90 for(int i=0; i<Len; ++i)H=H*M+s1[i]; 91 for(int i=1; i<n; ++i) { 92 int u,v; 93 scanf("%d%d",&u,&v); 94 addedge(u,v); 95 addedge(v,u); 96 } 97 dfs1(1,0,1),dfs2(1,1); 98 build(rt); 99 while(m--) { 100 int f,u,v; 101 char ch; 102 scanf("%d",&f); 103 if(f==1)scanf("%d%d",&u,&v),printf("%d\n",qry2(u,v)); 104 else scanf("%d %c",&u,&ch),upd(dfn[u],ch); 105 } 106 return 0; 107 }
原文地址:https://www.cnblogs.com/asdfsag/p/11623017.html
时间: 2024-10-06 04:31:43