bzoj4811[Ynoi2017]由乃的OJ
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4811
第一次写树链剖分。搞清楚原树的点和线段树上的点的对应关系很重要。
(树链剖分之所以能对应到线段树上,是因为走的不是重链就是点,都是dfs序连续区间。)
本题有64位,不用像“睡觉困难综合征”那样每一位循环,弄到unsigned long long里就能一起弄。
注意一下合并,想想就能明白。还要注意方向。
感觉是一道很好的模板题。抄了TJ的代码,觉得写得好好。(https://blog.csdn.net/a1799342217/article/details/78818480)
#include<iostream> #include<cstdio> #include<cstring> #define ull unsigned long long using namespace std; const int N=1e5+5; int n,m,lm,head[N],xnt,tot,top[N],fa[N],dep[N],id[N],rnk[N],son[N],siz[N]; ull op[N][2]; struct Dt{ ull p0,p1;//都是ull! }; struct Edge{ int next,to; Edge(int n=0,int t=0):next(n),to(t) {} }edge[N<<1]; struct Node{ int l,r,ls,rs; Dt fr,fl; }a[N<<1]; void added(int x,int y) { edge[++xnt]=Edge(head[x],y);head[x]=xnt; edge[++xnt]=Edge(head[y],x);head[y]=xnt; } void dfs1(int cr,int depth) { dep[cr]=depth;siz[cr]=1; for(int i=head[cr],v;i;i=edge[i].next) if((v=edge[i].to)!=fa[cr]) { fa[v]=cr;dfs1(v,depth+1);siz[cr]+=siz[v]; if(siz[v]>siz[son[cr]])son[cr]=v; } } void dfs2(int cr) { id[cr]=++tot;rnk[tot]=cr; if(!son[cr])return; top[son[cr]]=top[cr],dfs2(son[cr]); for(int i=head[cr],v;i;i=edge[i].next) if((v=edge[i].to)!=son[cr]&&v!=fa[cr]) { top[v]=v;dfs2(v); } } Dt updt(ull op,ull w) { Dt ret; if(op==1)ret.p0=0&w,ret.p1=(~0)&w; if(op==2)ret.p0=0|w,ret.p1=(~0)|w; if(op==3)ret.p0=0^w,ret.p1=(~0)^w; return ret; } Dt pshp(Dt x,Dt y) { Dt ret; ret.p0=(x.p0&y.p1)|(~x.p0&y.p0); ret.p1=(x.p1&y.p1)|(~x.p1&y.p0); return ret; } void build(int l,int r,int cr) { a[cr].l=l;a[cr].r=r; if(l==r){a[cr].fl=a[cr].fr=updt(op[rnk[l]][0],op[rnk[l]][1]);return;}//rnk[l]! int mid=l+r>>1; tot++;a[cr].ls=tot; build(l,mid,tot); tot++;a[cr].rs=tot; build(mid+1,r,tot); a[cr].fl=pshp(a[a[cr].ls].fl,a[a[cr].rs].fl); a[cr].fr=pshp(a[a[cr].rs].fr,a[a[cr].ls].fr); } void mdfy(int cr,int x,ull op,ull w) { if(a[cr].l==a[cr].r) { a[cr].fl=a[cr].fr=updt(op,w);return; } int mid=a[cr].l+a[cr].r>>1; if(x<=mid)mdfy(a[cr].ls,x,op,w); else mdfy(a[cr].rs,x,op,w); a[cr].fl=pshp(a[a[cr].ls].fl,a[a[cr].rs].fl); a[cr].fr=pshp(a[a[cr].rs].fr,a[a[cr].ls].fr); } Dt srch(int cr,int l,int r,int fx) { if(a[cr].l>=l&&a[cr].r<=r) if(fx)return a[cr].fr; else return a[cr].fl; int mid=a[cr].l+a[cr].r>>1;//a[cr].l a[cr].r !l !r if(mid>=r)return srch(a[cr].ls,l,r,fx); else if(mid<l)return srch(a[cr].rs,l,r,fx); else return pshp(srch(fx?a[cr].rs:a[cr].ls,l,r,fx),srch(fx?a[cr].ls:a[cr].rs,l,r,fx)); } Dt find(int x,int y) { Dt ans1=updt(3,0),ans2=updt(3,0); while(top[x]!=top[y]) if(dep[top[x]]>dep[top[y]]) { ans1=pshp(ans1,srch(1,id[top[x]],id[x],1));//1(区间是从上到下,故从右可接上当前) x=fa[top[x]]; } else { ans2=pshp(srch(1,id[top[y]],id[y],0),ans2); y=fa[top[y]]; } if(dep[x]<=dep[y])return pshp(pshp(ans1,srch(1,id[x],id[y],0)),ans2); else return pshp(pshp(ans1,srch(1,id[y],id[x],1)),ans2);//1 } void query(int x,int y,ull z) { Dt ans=find(x,y);ull ret=0,sum=0; for(int i=lm-1;i>=0;i--) if((1ull<<i)&ans.p0)ret|=(1ull<<i); else if(((1ull<<i)&ans.p1)&&(sum|(1ull<<i))<=z) sum|=(1ull<<i),ret|=(1ull<<i); printf("%llu\n",ret); } int main() { scanf("%d%d%d",&n,&m,&lm); for(int i=1;i<=n;i++)scanf("%llu%llu",&op[i][0],&op[i][1]); int x,y; for(int i=1;i<n;i++)scanf("%d%d",&x,&y),added(x,y); dfs1(1,1);top[1]=1;dfs2(1);tot=1;build(1,n,1); ull z;int q; while(m--) { scanf("%d%d%d%llu",&q,&x,&y,&z); if(q==2)mdfy(1,id[x],y,z);/////id[x] else query(x,y,z); } return 0; }