JZOJ 5915 【NOIP2018模拟10.19】明日之星

明日之星

Description

n n n个由 ‘ A ’ 、 ‘ C ’ 、 ‘ G ’ 、 ‘ T ’ 、 ‘ U ’ ‘A’、‘C’、‘G’、‘T’、‘U’ ACGTU五种字符组成的字符串 s i s_i si
第i个字符串还会有一个权值 a i a_i ai
点与点之间连成了一棵无根树。
给出 q q q个询问,每次给出一个字符串 S S S和两个整数 u , v u,v u,v,对于树上 u u u v v v的路径上任意的点 i i i,都会贡献 a i a_i ai*( s i s_i si S S S中出现的次数)。
同时有可能会有修改操作,修改 a i a_i ai的权值。
强制在线。

Data Constrints

1 ≤ a i ≤ 1 0 3 1\leq a_i\leq 10^3 1ai103       1 ≤ n , q ≤ 2 ∗ 1 0 5 \ \ \ \ \ 1\leq n,q \leq 2*10^5      1n,q2105        1 ≤ ∑ ∣ S ∣ , ∑ ∣ s ∣ ≤ 4 ∗ 1 0 5 \ \ \ \ \ \ 1\leq \sum |S|,\sum |s| \leq 4*10^5       1S,s4105

Solution

首先考虑如何快速查找一条链上的点对某个 S S S的贡献,对这些点对应的字符串建 A C AC AC自动机,在对应的位置加上 a a a的值,之后把 S S S丢到 A C AC AC自动机上跑,每到自动机上的一个状态答案就加上它 f a i l fail fail链上所有状态的权值和。

接下来考虑括号序,任何一条树上的链都可以拆成括号序上至多两段区间来表示,接着用对括号序建一棵线段树,对于线段树的某个区间 [ l , r ] [l,r] [l,r],将 [ l , r ] [l,r] [l,r]上的所有点对应的字符串建 A C AC AC自动机,接着再建出 f a i l fail fail反链树,不难发现这样做时间复杂度和空间复杂度都是 O ( ∑ ∣ s ∣   l o g   n ) O(\sum |s|\ log\ n) O(s log n)的。接着再考虑 a a a,当某个点加上某个权值时,会对其 f a i l fail fail反链树上的子树中所有点都造成贡献,所以只需对每个线段树区间再用一个树状数组来维护即可,这样的时间复杂度是 O ( ∑ ∣ s ∣   l o g 2   n ) O(\sum |s|\ log^2\ n) O(s log2 n)

询问的话,就找出 u u u v v v路径对应括号序的 l o g   n log\ n log n个线段树区间,依次把 S S S丢到这 l o g   n log\ n log n个区间的 A C AC AC自动机上跑,用树状数组统计贡献。
修改也差不多,可以发现也是一样的把需要修改的 l o g   n log\ n log n个区间抽出来,找到它在该区间对应的 A C AC AC自动机上的位置(这个需要提前预处理),在树状数组上修改即可。

总的复杂度 O ( ∑ ∣ s ∣ + ∑ ∣ S ∣ + q   l o g 2   n ) O(\sum |s|+\sum |S|+q\ log^2\ n) O(s+S+q log2 n)

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#pragma GCC optimize(3)
#pragma GCC optimize(2)

#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)

using namespace std;
typedef long long ll;
const ll N=22e4,M=N<<1,U=M<<2,K=M*20;

struct note{
	int c[5],fail,dfn,tail,val;
}k[K];

int n,tp,zy[200],uy,x,y,op,ans,fs,oo,l,keep,lr,q,rp,u,r,j;
char t[M];
int s[M],d[U];
int zb[M],yb[M];
int v[M],fa[M],dep[M];
int la[M],ne[U],lb[U];

int dq,be[U],en[U],cd[U],tr[K];

int bh[M],pre[M],bac[M],we[M];
int xs[M];
int f[N][20],po[M][30];

inline void llb(int a,int b)
{ne[++oo]=la[a]; la[a]=oo; lb[oo]=b;}

inline void dg(int o)
{
	pre[o]=++op;
	bh[op]=o; xs[op]=v[o]; 
	for(int y=la[o];y;y=ne[y])
	if(!fa[lb[y]]){
		fa[lb[y]]=f[lb[y]][0]=o;
		dep[lb[y]]=dep[o]+1;
		for(l=0;f[f[lb[y]][l]][l];++l)
		f[lb[y]][l+1]=f[f[lb[y]][l]][l];
		dg(lb[y]);
	}
	bac[o]=++op;
	bh[op]=o; xs[op]=-v[o];
}

inline void dfs(int o)
{
	k[o].dfn=k[o].tail=++uy;
	for(int y=la[o-keep];y;y=ne[y]){
		dfs(lb[y]);
		k[o].tail=k[lb[y]].tail;
	}
}

inline void cor(int o,int b,int del)
{
	for(;b<=cd[o];b=b+(b&(-b)))
	tr[b+be[o]-1]+=del;
}

inline void make(int o,int l,int r)
{
	be[o]=++dq; uy=oo=0;
	k[dq].fail=dq;
	fo(i,l,r){
		int mq=be[o]; int y=bh[i];
		fo(l,zb[y],yb[y]){
			if(!k[mq].c[s[l]])k[mq].c[s[l]]=++dq;
			mq=k[mq].c[s[l]];
		}
		k[mq].val+=xs[i];
		po[i][++po[i][0]]=mq;
	}
	d[1]=be[o];
	en[o]=dq;
	cd[o]=en[o]-be[o]+1;
	int le=0,ri=1;
	fo(i,1,cd[o])la[i]=0;
	keep=be[o]-1;
	while(le<ri){
		r=d[++le];
		fo(i,0,4)if(k[r].c[i]){
			u=k[r].c[i];
			d[++ri]=u;
			j=k[r].fail;
			for(;j!=be[o]&&!k[j].c[i];)j=k[j].fail;
			if(k[j].c[i]!=u&&k[j].c[i])k[u].fail=k[j].c[i];
			else k[u].fail=be[o];
			llb(k[u].fail-keep,u);
		}
	}
	dfs(be[o]);
	fo(i,be[o],en[o])
	if(k[i].val!=0)cor(o,k[i].dfn,k[i].val),cor(o,k[i].tail+1,-k[i].val);
}

inline void build(int o,int l,int r)
{
	make(o,l,r);
	if(l==r)return;
	int mid=l+r>>1;
	build(o<<1,l,mid); build((o<<1)^1,mid+1,r);
}

inline void modify(int o,int l,int r,int posi,int c,int g)
{
	int wz=po[posi][g];
	cor(o,k[wz].dfn,c); cor(o,k[wz].tail+1,-c);
	if(l==r)return;
	int mid=l+r>>1;
	if(posi<=mid)modify(o<<1,l,mid,posi,c,g+1);
	else modify((o<<1)^1,mid+1,r,posi,c,g+1);
}

inline int ggg(int o,int b)
{
	int yy=0;
	for(;b;b=b-(b&(-b)))yy=yy+tr[b+be[o]-1];
	return yy;
}

inline int get(int a,int b)
{
	for(int l=19;l>=0;--l)if(dep[f[b][l]]>=dep[a])b=f[b][l];
	for(int l=19;l>=0;--l)if(f[b][l]!=f[a][l])a=f[a][l],b=f[b][l];
	fs=b;
	if(a!=b)a=fa[a];
	return a;
}

inline int ask(int o,int l,int r,int le,int ri)
{
	if(l==le&&r==ri){
		int lj=0;
		int dq=be[o];
		fo(i,1,lr){
			for(;!k[dq].c[we[i]]&&dq!=be[o];)dq=k[dq].fail;
			if(k[dq].c[we[i]])dq=k[dq].c[we[i]];
			if(dq!=be[o])lj=lj+ggg(o,k[dq].dfn);
		}
		return lj;
	}
	int mid=l+r>>1;
	if(ri<=mid)return ask(o<<1,l,mid,le,ri);
	else if(le>mid)return ask((o<<1)^1,mid+1,r,le,ri);
	else return ask(o<<1,l,mid,le,mid)+ask((o<<1)^1,mid+1,r,mid+1,ri);
}

int main()
{
	scanf("%d%d",&n,&tp);
	zy['A']=0; zy['C']=1; zy['G']=2; zy['T']=3; zy['U']=4;
	fo(i,1,n){
		scanf("%s",t+1);
		zb[i]=yb[i-1]+1;
		yb[i]=yb[i-1]+strlen(t+1);
		fo(l,zb[i],yb[i])s[l]=zy[t[l-yb[i-1]]];
	}
	fo(i,1,n)scanf("%d",&v[i]);
	fo(i,1,n-1){
		scanf("%d%d",&x,&y);
		llb(x,y); llb(y,x);
	}
	fa[1]=-1; dep[1]=1; dg(1);
	build(1,1,op);
	scanf("%d",&q);
	ans=0;
	fo(i,1,q){
		scanf("%d%d%d",&rp,&x,&y);
		x^=(ans*tp);
		y^=(ans*tp);
		if(rp==2){
			int zl=y-v[x];
			modify(1,1,op,pre[x],zl,1);
			modify(1,1,op,bac[x],-zl,1);
			v[x]=y;
		}else{
			scanf("%s",t+1);
			lr=strlen(t+1);
			fo(l,1,lr)we[l]=zy[t[l]];
			if(dep[x]>dep[y])swap(x,y);
			int lca=get(x,y);
			if(lca==x)ans=ask(1,1,op,pre[x],pre[y]);
			else ans=ask(1,1,op,pre[lca],pre[x])+ask(1,1,op,pre[fs],pre[y]);
			printf("%d\n",ans);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值