树剖 然后开32棵线段树 记录1/0 从左/右 经过 变成的值
然后就是一些区间合并成一条有向路径
#include<cstdio> #include<cstdlib> #include<algorithm> #define V G[p].v #define nand(x,y) (!((x)&(y))) #define digit(x,k) (((x)>>((k)-1))&1) using namespace std; typedef long long ll; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') c=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(char &x){ for (x=nc();x!='Q' && x!='R';x=nc()); } const int N=100005; struct SEGTREE{ struct node{ bool f[2][2]; // 0 right 1 left node(int d=-1){ if (d==-1) { f[0][1]=f[1][1]=1; f[0][0]=f[1][0]=0; } else { f[0][1]=f[1][1]=nand(1,d); f[0][0]=f[1][0]=nand(0,d); } } friend node operator + (const node A,const node B){ node ret; ret.f[0][1]=B.f[0][A.f[0][1]]; ret.f[0][0]=B.f[0][A.f[0][0]]; ret.f[1][1]=A.f[1][B.f[1][1]]; ret.f[1][0]=A.f[1][B.f[1][0]]; return ret; } }T[N*4]; int M; void Build(int n,int *a,int k){ for (M=1;M<n+2;M<<=1); for (int i=1;i<=n;i++) T[M+i]=node(digit(a[i],k)); for (int i=M-1;i;i--) T[i]=T[i<<1]+T[i<<1|1]; } node Query(int s,int t){ node lret,rret,ret; for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) lret=lret+T[s^1]; if ( t&1) rret=T[t^1]+rret; } return lret+rret; } void Change(int s,int r){ T[s+=M]=node(r); while (s>>=1) T[s]=T[s<<1]+T[s<<1|1]; } }Seg[35]; struct edge{ int u,v,next; }; edge G[2*N]; int head[N],inum; inline void add(int u,int v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p; } int size[N],depth[N],fat[N]; int clk,tid[N],top[N]; void dfs(int u,int fa){ fat[u]=fa; depth[u]=depth[fa]+1; size[u]=1; for (int p=head[u];p;p=G[p].next) if (V!=fa) dfs(V,u),size[u]+=size[V]; } void find(int u,int fa,int z){ tid[u]=++clk; top[u]=z; int maximum=0,son=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && size[V]>maximum) maximum=size[son=V]; if (son) find(son,u,z); for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son) find(V,u,V); } inline int LCA(int u,int v){ for (;top[u]!=top[v];u=fat[top[u]]) if (depth[top[u]]<depth[top[v]]) swap(u,v); if (depth[u]>depth[v]) swap(u,v); return u; } int n,m,K; int val[N]; int Up(int org,int u,int lca,int k){ SEGTREE::node ret; for (;top[u]!=top[lca];u=fat[top[u]]) ret=Seg[k].Query(tid[top[u]],tid[u])+ret; ret=Seg[k].Query(tid[lca],tid[u])+ret; return ret.f[1][org]; } int Down(int org,int u,int lca,int k){ SEGTREE::node ret; for (;top[u]!=top[lca];u=fat[top[u]]) ret=Seg[k].Query(tid[top[u]],tid[u])+ret; if (u!=lca) ret=Seg[k].Query(tid[lca]+1,tid[u])+ret; return ret.f[0][org]; } inline ll Solve(int u,int v){ int lca=LCA(u,v),xx; ll ans=0; for (int k=1;k<=K;k++) { xx=0; xx=Up(xx,u,lca,k); xx=Down(xx,v,lca,k); ans+=xx*(1LL<<(k-1)); } return ans; } inline void Replace(int u,int r){ for (int k=1;k<=K;k++) Seg[k].Change(tid[u],digit(r,k)); } int itmp[N]; int main() { int iu,iv,Q; char order; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(Q); read(K); for (int i=1;i<=n;i++) read(val[i]); for (int i=1;i<n;i++) read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum); dfs(1,0); find(1,0,1); for (int i=1;i<=n;i++) itmp[tid[i]]=val[i]; for (int k=1;k<=K;k++) Seg[k].Build(n,itmp,k); while (Q--) { read(order); read(iu); read(iv); if (order=='Q') printf("%lld\n",Solve(iu,iv)); else Replace(iu,iv); } return 0; }