BZOJ3862 Little Devil I 树链剖分
原文链接http://www.cnblogs.com/zhouzhendong/p/8081514.html
题目传送门 - BZOJ3862
题意概括
一棵树,n个点,边权为黑或者白,支持3重操作:
1.链上颜色翻转
2.对于一条链,把有一个点在这条链上的边全部翻转颜色
3.询问一条链上有多少黑色。
题解
毒瘤题。
对于1、3都是基础操作,很简单。
主要是2.
2的话,只需要打区间打标记,表示那些点的连向轻儿子的边全部翻转。然后修改的时候还有一堆特判(具体看代码)
这题数据坑。
有a==b的情况,小心了。我被坑了一个下午。
我是怎么找到这个数据的呢?
if (a==b) OLE();
void OLE(){ int a[100]; for (int i=23333;;i=i*i) printf("233"); }
代码
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; bool isd(char ch){return '0'<=ch&&ch<='9';} int read(){ int x=0; char ch=getchar(); while (!isd(ch)) ch=getchar(); while (isd(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); return x; } const int N=100005; struct Gragh{ int cnt,y[N*2],nxt[N*2],fst[N]; void clear(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; } }g; int T,n,q,cnp; int size[N],fa[N],depth[N],son[N],p[N],ap[N],top[N]; void Get_Gen_Info(int rt,int pre,int d){ size[rt]=1,son[rt]=-1,fa[rt]=pre,depth[rt]=d; for (int i=g.fst[rt];i;i=g.nxt[i]) if (g.y[i]!=pre){ int s=g.y[i]; Get_Gen_Info(s,rt,d+1); size[rt]+=size[s]; if (son[rt]==-1||size[s]>size[son[rt]]) son[rt]=s; } } void Get_Top(int rt,int tp){ top[rt]=tp; ap[p[rt]=++cnp]=rt; if (!~son[rt]) return; Get_Top(son[rt],tp); for (int i=g.fst[rt];i;i=g.nxt[i]){ int s=g.y[i]; if (s!=fa[rt]&&s!=son[rt]) Get_Top(s,s); } } const int S=N*4; struct Tree{ int sum,size,r,sr; }t[S]; void build(int rt,int L,int R){ t[rt].size=R-L+1,t[rt].sum=t[rt].r=t[rt].sr=0; if (L==R) return; int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; build(ls,L,mid); build(rs,mid+1,R); } void pushup(int rt){ int ls=rt<<1,rs=ls|1; t[rt].sum=t[ls].sum+t[rs].sum; } void pushdown(int rt){ int ls=rt<<1,rs=ls|1; int &sr=t[rt].sr,&r=t[rt].r; if (sr) t[ls].sr^=1,t[rs].sr^=1,sr=0; if (r){ t[ls].r^=1,t[ls].sum=t[ls].size-t[ls].sum; t[rs].r^=1,t[rs].sum=t[rs].size-t[rs].sum; r=0; } } void update(int rt,int L,int R,int xL,int xR,int op){ if (R<xL||L>xR) return; if (xL<=L&&R<=xR){ if (op==1){ t[rt].sum=t[rt].size-t[rt].sum; t[rt].r^=1; } else t[rt].sr^=1; return; } pushdown(rt); int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; update(ls,L,mid,xL,xR,op); update(rs,mid+1,R,xL,xR,op); pushup(rt); } int query(int rt,int L,int R,int xL,int xR){ if (R<xL||L>xR) return 0; if (xL<=L&&R<=xR) return t[rt].sum; pushdown(rt); int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; return query(ls,L,mid,xL,xR)+query(rs,mid+1,R,xL,xR); } int asksr(int rt,int L,int R,int pos){ if (L==R) return t[rt].sr; pushdown(rt); int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; if (pos<=mid) return asksr(ls,L,mid,pos); else return asksr(rs,mid+1,R,pos); } void Tupdate(int a,int b,int op){ if (a==b) return; int f1=top[a],f2=top[b]; while (f1!=f2){ if (depth[f1]<depth[f2]) swap(f1,f2),swap(a,b); update(1,1,n,p[f1],p[a],op); if (op==2){ update(1,1,n,p[f1],p[f1],1); if (~son[a]) update(1,1,n,p[son[a]],p[son[a]],1); } a=fa[f1],f1=top[a]; } if (depth[a]>depth[b]) swap(a,b); if (op==2){ update(1,1,n,p[a],p[b],2); update(1,1,n,p[a],p[a],1); if (~son[b]) update(1,1,n,p[son[b]],p[son[b]],1); } else if (a!=b) update(1,1,n,p[son[a]],p[b],op); } int Tquery(int a,int b){ int f1=top[a],f2=top[b],ans=0; while (f1!=f2){ if (depth[f1]<depth[f2]) swap(f1,f2),swap(a,b); if (f1!=a) ans+=query(1,1,n,p[son[f1]],p[a]); ans+=query(1,1,n,p[f1],p[f1])^asksr(1,1,n,p[fa[f1]]); a=fa[f1],f1=top[a]; } if (depth[a]>depth[b]) swap(a,b); if (a!=b) ans+=query(1,1,n,p[son[a]],p[b]); return ans; } int main(){ T=read(); while (T--){ n=read(); g.clear(); for (int i=1,a,b;i<n;i++){ a=read(),b=read(); g.add(a,b),g.add(b,a); } cnp=0; Get_Gen_Info(1,0,0); Get_Top(1,1); build(1,1,n); q=read(); while (q--){ int op,a,b; op=read(),a=read(),b=read(); if (a==b){ if (op==3) puts("0"); if (op==2){ update(1,1,n,p[a],p[a],2); if (~son[a]) update(1,1,n,p[son[a]],p[son[a]],1); if (fa[a]) update(1,1,n,p[a],p[a],1); } continue; } if (op<3) Tupdate(a,b,op); if (op==3) printf("%d\n",Tquery(a,b)); } } return 0; }