【JZOJ5915】明日之星

Description

n个点形成一棵树,每个点有一个由‘A’、‘G’、‘C’、‘T’、‘U’组成的字符串s_i,同时有一个权值 a i a_i ai。现在要支持在线单点修改 a i a_i ai,或给出询问串 S S S,查询一条路径上的点 a i ⋅ b i a_i\cdot b_i aibi的和, b i b_i bi s i s_i si S S S中出现次数。

Solution

考虑链怎么做:我们可以维护一个线段树分治结构,对于一个分治区间,维护这里所有点的AC自动机,记 f i f_i fi i i i节点在fail树上到根节点的 a i a_i ai的和,这可以用树状数组维护。
转到树上,我们发现这里权值是累加的,我们可以用括号序,左括号加上权值,右括号再减去,这样树上一条路径就是维护两段区间和。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
const int N=4e5+10,M=4e5+10,Z=19;
flag
int L[N],ln[N],a[N],tot=0,m=0;
int S[M];
struct edge{
	int to[M],nx[M],ls[M*20],num;
	void link(int u,int v){
		to[++num]=v,nx[num]=ls[u],ls[u]=num;
	}
}T,F;
int ch(char c) {
	return (c>'A')+(c>'C')+(c>'G')+(c>'T');
}
int dep[N],fa[N][Z+5],n;
int tr[M*20][5],fail[M*20];
int ct[M*20];
int pl[N],pr[N],z[N<<1],rt[N<<2],sz[N<<2];
int pos[N<<1][Z+5];
char s[M];
void pre(int x,int fr){
	fa[x][0]=fr,dep[x]=dep[fr]+1;
	fo(i,1,Z) fa[x][i]=fa[fa[x][i-1]][i-1];
	z[pl[x]=++m]=x;
	for(int i=T.ls[x];i;i=T.nx[i]){
		int v=T.to[i];
		if(v==fr) continue;
		pre(v,x);
	}
	z[pr[x]=++m]=-x;
}
queue<int> d;
int tt=0;
int le[M*20],ri[M*20];
void bl(int x){
	le[x]=++tt;
	for(int i=F.ls[x];i;i=F.nx[i]) bl(F.to[i]);
	ri[x]=tt;
}
int gg=0;
void build(int v=1,int l=1,int r=m,int dp=1){
	rt[v]=++tot;
	fo(i,l,r){
		int p=rt[v],x=z[i],t=x<0?-x:x;
		fo(j,L[t],L[t]+ln[t]-1){
			int c=S[j];
			if(!tr[p][c]) tr[p][c]=++tot;
			p=tr[p][c];
		}
		pos[x+n][dp]=p;
	}
	d.push(rt[v]);
	while(!d.empty()){
		int x=d.front();d.pop();
		fo(i,0,4){
			int o=tr[x][i];
			if(!o) continue;
			int p=fail[x];
			while(p && !tr[p][i]) p=fail[p];
			fail[o]=tr[p][i]?tr[p][i]:rt[v];
			d.push(o);
		}
	}
	fo(i,rt[v]+1,tot) F.link(fail[i],i);
	tt=0,bl(rt[v]),sz[v]=tt+1,tot++;
	fo(i,rt[v]+1,tot) F.ls[fail[i]]=0;F.num=0;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(v<<1,l,mid,dp+1),build(v<<1|1,mid+1,r,dp+1);
}
void ad(int x,int t,int v){
	for(;x<=sz[v];x+=x&-x) ct[x+rt[v]-1]+=t; 
}
int sum(int x,int v){
	int tmp=0;
	for(;x;x-=x&-x) tmp+=ct[x+rt[v]-1];
	return tmp;
}
int qu(int v){
	int l=strlen(s+1),p=rt[v],tmp=0;
	fo(i,1,l){
		int c=ch(s[i]);
		while(p && !tr[p][c]) p=fail[p];
		p=tr[p][c]?tr[p][c]:rt[v];
		tmp+=sum(le[p],v);
	}
	return tmp;
}
void add(int x,int t,int v=1,int l=1,int r=m,int dp=1){
	int p=pos[z[x]+n][dp];
	ad(le[p],t,v),ad(ri[p]+1,-t,v);
	if(l==r) return;
	int mid=(l+r)>>1;
	x<=mid?add(x,t,v<<1,l,mid,dp+1):add(x,t,v<<1|1,mid+1,r,dp+1);
}
int qsum(int x,int y,int v=1,int l=1,int r=m){
	if(l==x && r==y) return qu(v);
	int mid=(l+r)>>1;
	if(y<=mid) return qsum(x,y,v<<1,l,mid);
	else if(x>mid) return qsum(x,y,v<<1|1,mid+1,r);
	else return qsum(x,mid,v<<1,l,mid)+qsum(mid+1,y,v<<1|1,mid+1,r);
}
int ed;
int lca(int u,int v){
	fd(i,Z,0) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
	if(u==v) return u;
	fd(i,Z,0) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
	ed=v;
	return fa[u][0];
}
int main()
{
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	int tp;
	scanf("%d %d",&n,&tp);
	fo(i,1,n){
		scanf("%s",s+1);
		ln[i]=strlen(s+1);
		L[i]=tot+1,tot+=ln[i];
		fo(j,L[i],L[i]+ln[i]-1) S[j]=ch(s[j-L[i]+1]);
	}
	fo(i,1,n) scanf("%d",&a[i]);
	fo(i,2,n){
		int u,v;
		scanf("%d %d",&u,&v);
		T.link(u,v),T.link(v,u);
	}
	pre(1,0);
	tot=0,build();
	fo(i,1,n){
		add(pl[i],a[i]);
		add(pr[i],-a[i]);
	}
	int q;
	scanf("%d",&q);
	int ans=0;
	while(q--){
		int op,x,y;
		scanf("%d %d %d",&op,&x,&y),x^=ans*tp,y^=ans*tp;
		if(op==1){
			scanf("%s",s+1);
			if(dep[x]<dep[y]) swap(x,y);
			int lc=lca(x,y);
			ans=lc==y?qsum(pl[lc],pl[x]):qsum(pl[lc],pl[x])+qsum(pl[ed],pl[y]);
			printf("%d\n",ans);
		}
		else{
			int w=y-a[x];a[x]=y;
			add(pl[x],w),add(pr[x],-w);
		}
	}
}

posted @ 2018-10-19 22:10  sadstone  阅读(57)  评论(0编辑  收藏  举报