题目大意:给出一棵n个点的树,每个点有一个运算符(与、或、异或)和一个数,支持两种操作,第一种修改一个点的运算符和数,第二种给出x,y,z,询问若有一个0~z之间的数从点x走到点y(简单路径),并且对路径上经过的点做对应的运算,最终最大能是多少。(n,操作数<=100,000,数字在[0,2^64)之间)
思路:洛谷改编NOI的一道神题,树剖/LCT维护若一开始全是0/全是1,经过一条链后各位会变成什么,用位运算合并信息,然后每个询问,从高位往低位贪心,每次取0和1中经过这条链后得到的较大值,若相同则取0,总复杂度O(nlogn)/O(nlogn^2)。
#include<cstdio> #include<algorithm> using namespace std; #define ll unsigned long long inline ll read() { ll x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 100000 #define L(x) c[x][0] #define R(x) c[x][1] struct edge{int nx,t;}e[MN*2+5]; struct data{ll f[2];}lf[MN+5],rf[MN+5],f[MN+5]; data operator+(const data&a,const data&b) { return (data){~a.f[0]&b.f[0]|a.f[0]&b.f[1], ~a.f[1]&b.f[0]|a.f[1]&b.f[1]}; } int h[MN+5],en,fa[MN+5],c[MN+5][2],rv[MN+5],z[MN+5],zn; inline void ins(int x,int y) { e[++en]=(edge){h[x],y};h[x]=en; e[++en]=(edge){h[y],x};h[y]=en; } void dfs(int x) { for(int i=h[x];i;i=e[i].nx) if(e[i].t!=fa[x])fa[e[i].t]=x,dfs(e[i].t); } inline void up(int x) { lf[x]=rf[x]=f[x]; if(L(x))lf[x]=lf[L(x)]+lf[x],rf[x]=rf[x]+rf[L(x)]; if(R(x))lf[x]=lf[x]+lf[R(x)],rf[x]=rf[R(x)]+rf[x]; } void init(int x,int o,ll z) { if(o==1)f[x]=(data){0,z}; if(o==2)f[x]=(data){z,-1}; if(o==3)f[x]=(data){z,~z}; up(x); } inline void rev(int x){rv[x]^=1;swap(L(x),R(x));swap(lf[x],rf[x]);} inline void down(int x){if(rv[x])rev(L(x)),rev(R(x)),rv[x]=0;} inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;} void rotate(int x) { int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1; if(isc(f))c[ff][R(ff)==f]=x; fa[f]=x;fa[x]=ff;fa[c[x][r]]=f; c[f][l]=c[x][r];up(c[x][r]=f); } void splay(int x) { for(int i=z[zn=1]=x;isc(i);)i=z[++zn]=fa[i]; for(;zn;--zn)down(z[zn]); for(int f;isc(x);rotate(x)) if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f); up(x); } void access(int x) { for(int i=0;x;x=fa[i=x])splay(x),R(x)=i; } int main() { int n,m,i,x,u;ll z,ans,f0,f1; n=read();m=read();read(); for(i=1;i<=n;++i)x=read(),init(i,x,read()); for(i=1;i<n;++i)ins(read(),read()); dfs(1); while(m--) if(read()<2) { access(x=read());splay(x);rev(x); access(x=read());splay(x); z=read();ans=u=0; for(i=64;i--;) if(u||(z&(1LLU<<i))) { f0=lf[x].f[0]&(1LLU<<i); f1=lf[x].f[1]&(1LLU<<i); if(f0>=f1)u=1; ans|=max(f0,f1); } else ans|=lf[x].f[0]&(1LLU<<i); printf("%llu ",ans); } else x=read(),i=read(),splay(x),init(x,i,read()); }