明日之星

2 篇文章 0 订阅
1 篇文章 0 订阅

Time Limits: 5000 ms Memory Limits: 524288 KB

Description
n位舞台少女各自有一个番号,番号是由‘A’、‘C’、‘G’、‘T’、‘U’五种字符组成的字符串,某种未知力量导致不同的舞台少女的番号可能相同。
我们把第i位舞台少女的番号记作s[i],且每位舞台少女还会有一个梦想值a[i]。
舞台少女之间互相建立了友好的关系,如果把关系看作边,那么这是一棵无根树。
giraffe想了一种奇特的点名方式,每次点名它会有一个名单S,S也是由‘A’、‘G’、‘C’、‘T’、‘U’五种字符组成的字符串,然后它从第u位舞台少女走最短路到第v位舞台少女,对于途中经过的每位舞台少女x(包括u、v),x的分数为 番号s[x]在S中出现的次数 * 梦想值a[x],giraffe想知道分数之和。
当然,舞台少女们随着心情的变化梦想值也是会改变的。
giraffe:“I see.”
谁也不知道giraffe知道的分数和是多少,所以拜托你了。
由于gireffe喜欢未知的舞台,所以本题强制在线。

Input
第一行两个正整数n,tp,表示一共有n位舞台少女,tp是强制在线参数,tp=0或1。
接下来n行,每行一个非空字符串s[i],表示第i位舞台少女的番号,s[i]由‘A’、‘G’、‘C’、‘T’、‘U’五种字符组成。
接下来一行n个正整数,第i个整数a[i]表示第i位少女一开始的梦想值。
再接下来n-1行,每行两个数x,y,表示第x位舞台少女和第y位舞台少女有友好的关系。
一行一个整数Q,表示一共有Q次询问或修改。
最后Q行,每一行第一个整数op,表示操作类型。
若op=1,表示这次操作为询问,接下来2个数u_,v_,真正的 u = u x o r ( l a s t a n s ∗ t p ) , v = v x o r ( l a s t a n s ∗ t p ) u=u_xor (lastans*tp),v=v_ xor (lastans*tp) u=uxor(lastanstp),v=vxor(lastanstp),和一个字符串S,含义如题。
若op=2,表示这次操作为修改,接下来两个数x_,c_,真正的 x = x x o r ( l a s t a n s ∗ t p ) , c = c x o r ( l a s t a n s ∗ t p ) x=x_xor (lastans*tp),c=c_ xor(lastans*tp) x=xxor(lastanstp)c=cxor(lastanstp),表示第x位舞台少女梦想值变为c了。
lastans表示上一次询问的答案,初值为0.

Output
对每一个op=1的询问,输出一行一个整数表示分数和。

Sample Input

5 0
AG
GC
CT
TU
AGCTU
1 1 1 1 1
1 2
1 3
4 2
2 5
3
1 3 5 AGCTU
2 1 2
1 4 3 ACGTU

Sample Output

4
1

Data Constraint
对于全部数据,保证任意时刻的a[i]满足:
1<=a[i]<=1000,ans<2^31,1<=n,Q<=200000,Sum(|s|),Sum(|S|)<=400000


Solution


先将n个串AC自动机的fail树搞出来
对于每个询问串扔到AC自动机上面跑,然后对每个点求答案累加起来
对于原树
在树上路径的查询拆成4个点到根的和
对于修改就相当于子树加,变为dfs序差分
对于fail树
要查询到根的值的和
修改要区间加,相当于dfs序上差分,询问相当于前缀和
所有过程就是三维偏序,离线好做,但在线呢?
有个东西叫做二进制分组,能够使用的条件是离线能够cdq分治,在线去做是,将当前所有操作二进制分组,就像树状数组的分法一样,比如21个操作,21=16+4+1,1~ 16分一组一棵主席树,17~ 20一颗,21一棵,每加一个操作往前能合并就合并,合并时重排一遍序,重新建一棵主席树,注意重建主席树要将废除的节点free掉,可以证明合并重建的复杂度是 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n)
查询,就在每个组的主席树中找即可,复杂度 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n)

常数挺大,过不了,但思路很好。。。

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i(a),_E_(b);i<=_E_;++i)
#define REP(i,a,b) for(int i(a),_E_(b);i<_E_;++i)
#define fd(i,a,b) for(int i(a),_E_(b);i>=_E_;--i)
#define pu putchar
#define ge getchar
#define N 400100
#define K 200100
#define M 30001000
#define lowbit(x) (x&(-x))

using namespace std;

void read(int &n){
	n=0;char c;for(;(c=ge())>'9'||c<'0';);
	for(;c>='0'&&c<='9';c=ge())n=(n<<1)+(n<<3)+c-48;
}
void write(int n){
	if(!n)pu(48);int t=0,b[11];
	for(;n;n/=10)b[++t]=n%10;while(t)pu(b[t--]+48);pu('\n');
}

int rt[N*4],fir[K],nex[N],to[N],dfl[K],dfr[K],fail[N],que[N],hd,tl,cnt,top,n,f[18][K];
int nxt[N][5],tot=1,go[N][5],lasans,tp,a[K],len,root=1,p[K],l[N],r[N],siz[N],deep[N];
int opl,opv,ct[22],total,opr,lg2[N],son[M][2],sum[M];
struct node{int a,b,v;}op[N*4],t1[N*4],t2[N*4];
bool cmp(node a,node b){return a.a<b.a;}

#define link(x,y) to[++top]=y,nex[top]=fir[x],fir[x]=top

int turn(char c){
	if(c=='A')return 0;
	if(c=='C')return 1;
	if(c=='T')return 2;
	if(c=='G')return 3;
	if(c=='U')return 4;
	return 5;
}
int find(int x,int col){
	for(;x && !nxt[x][col];x=fail[x]);return x;
}
void init_failtree(){
	for(hd=0,deep[que[tl=1]=root];hd^tl;){
		int x=que[++hd],y;
		fo(o,0,4){
			if(nxt[x][o]){
				que[++tl]=y=nxt[x][o];
				go[x][o]=y;
				int v=find(fail[x],o);
				if(nxt[v][o])v=nxt[v][o];else v=root;fail[y]=v;
			}else go[x][o]=go[fail[x]][o];
			if(x==root && !go[x][o])go[x][o]=root;
		}
	}
	fo(i,2,tot)link(fail[i],i);
	l[root]=1;siz[root]=1;
	for(hd=0,que[tl=1]=root;hd^tl;)
		for(int x=que[++hd],y,i=fir[x];i;i=nex[i])siz[que[++tl]=to[i]]=1;
	for(;hd;--hd){
		int x=que[hd];for(int i=fir[x];i;i=nex[i])siz[x]+=siz[to[i]];
	}
	while(++hd<=tl){
		int x=que[hd],sum=l[x];
		for(int i=fir[x];i;i=nex[i])l[to[i]]=sum+1,sum+=siz[to[i]];
		r[x]=sum;
	}
}
void dfs(int x){
	siz[x]=0;deep[x]=1;dfl[x]=1;
	for(hd=0,que[tl=1]=x;hd^tl;)
		for(int x=que[++hd],y,i=fir[x];i;i=nex[i])
			if((y=to[i])!=f[0][x])siz[y]=0,deep[y]=deep[x]+1,f[0][que[++tl]=y]=x;
	for(;hd;--hd){int x=que[hd];siz[f[0][x]]+=++siz[x];}
	while(++hd<=tl){
		int x=que[hd],sum=dfl[x],y;
		for(int i=fir[x];i;i=nex[i])if(to[i]!=f[0][x]){
			y=to[i];dfl[y]=sum+1;sum+=siz[y];
		}dfr[x]=sum;
	}
	fo(j,1,17)fo(i,1,n)f[j][i]=f[j-1][f[j-1][i]];
}
int lca(int x,int y){
	if(deep[x]>deep[y])return lca(y,x);
	while(deep[x]^deep[y])y=f[lg2[deep[y]-deep[x]]][y];
	if(x==y)return x;int t=deep[x];
	while(t){
		int i=lg2[t];if(f[i][x]^f[i][y])x=f[i][x],y=f[i][y],t-=1<<i;else t=(1<<i)-1;
	}return f[0][x];
}

void update(int u,int &v,int h,int t){
	sum[v=++cnt]=sum[u]+opv;son[v][0]=son[u][0];son[v][1]=son[u][1];
	if(h==t)return;int m=h+t>>1;
	(opl<=m)?update(son[u][0],son[v][0],h,m):update(son[u][1],son[v][1],m+1,t);
}
int query(int w,int h,int t){
	if(!w)return 0;
	if(opl<=h && opr>=t)return sum[w];
	int m=h+t>>1;
	return (opl<=m?query(son[w][0],h,m):0)+(opr>m?query(son[w][1],m+1,t):0); 
}
void put(int x,int l,int v){
	if(l>n || x>total)return;
	++top;siz[++tot]=1;op[top]=(node){x,l,v};
	while(tot>1 && siz[tot]==siz[tot-1]){
		int t=siz[tot],a=1,b=1;
		siz[--tot]=t+t;if(op[top-t].a<=op[top-t+1].a)continue;
		fo(i,1,t)t1[i]=op[top-t+i],t2[i]=op[top-t-t+i];
		fo(i,1,t+t)op[top-t-t+i]=(a<=t && (b>t || cmp(t1[a],t2[b])))?t1[a++]:t2[b++];
	}cnt=ct[tot-1];int las=0;
	fo(i,1,siz[tot]){
		int k=top-siz[tot]+i;opl=op[k].b,opv=op[k].v;
		update(rt[las],rt[k],1,n);las=k;
	}ct[tot]=cnt;
}
int get(int x,int l1,int r1,int l2,int r2){
	if(x<1)return 0;
	int sum=0,res=0;
	fo(i,1,tot){
		int h=sum+1,t=sum+siz[i],m,p=sum;
		sum+=siz[i];if(op[h].a>x)continue;
		while(h<=t)if(op[m=h+t>>1].a<=x)p=m,h=m+1;else t=m-1;
		opl=l1;opr=r1;res+=query(rt[p],1,n);
		opl=l2;opr=r2;res+=query(rt[p],1,n);
	}return res;
}

int main(){
	REP(i,2,N)lg2[i]=lg2[i>>1]+1;
	scanf("%d %d\n",&n,&tp);
	fo(i,1,n){
		int x=root;
		for(;;){
			int col=turn(ge());if(col>4)break;
			if(!nxt[x][col])nxt[x][col]=++tot;
			x=nxt[x][col];
		}p[i]=x;scanf("\n");
	}total=tot;init_failtree();
	fo(i,1,n)read(a[i]);
	top=0;
	memset(fir,0,sizeof fir);
	fo(i,2,n){
		int x,y;read(x);read(y);link(x,y);link(y,x);
	}dfs(1);
	int T=0;
	fo(i,1,n){
		op[++T]=(node){l[p[i]],dfl[i],a[i]};
		if(r[p[i]]<total)op[++T]=(node){r[p[i]]+1,dfl[i],-a[i]};
		if(dfr[i]<n)op[++T]=(node){l[p[i]],dfr[i]+1,-a[i]};
		if(r[p[i]]<total && dfr[i]<n)op[++T]=(node){r[p[i]]+1,dfr[i]+1,a[i]};
	}sort(op+1,op+T+1,cmp);
	fo(i,1,T){
		opl=op[i].b,opv=op[i].v;update(rt[i-1],rt[i],1,n);
	}siz[tot=1]=top=T;ct[1]=cnt;
	int q=0;scanf("%d",&q);
	fo(i,1,q){
		int ty,u,v;
		read(ty);read(u);read(v);u^=lasans*tp;v^=lasans*tp;
		if(ty==1){
			int L=lca(u,v);
			int ans=0,x=root;
			for(;;){
				int col=turn(ge());if(col>4)break;
				x=go[x][col];ans+=get(l[x],dfl[L]+1,dfl[u],dfl[f[0][L]]+1,dfl[v]);
			}
			write(lasans=ans);
		}else{
			int delta=v-a[u];a[u]=v;
			put(l[p[u]],dfl[u],delta);put(l[p[u]],dfr[u]+1,-delta);
			put(1+r[p[u]],dfl[u],-delta);put(1+r[p[u]],dfr[u]+1,delta);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值