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(lastans∗tp),v=vxor(lastans∗tp),和一个字符串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(lastans∗tp),c=cxor(lastans∗tp),表示第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;
}