bzoj 3862: Little Devil I (树链剖分+线段树)
来源:互联网 发布:java 协议开发 编辑:程序博客网 时间:2024/05/16 23:39
题目描述
传送门
题目大意:给出一棵n个点的树,有三种操作。
操作1:把x,y路径上所有边反色
操作2:把x,y路径上所有相邻的边反色,即一个点在路径上
操作3:询问x,y路径上黑边的个数。
注意刚开始的时候所有边均为白色。
题解
操作1,3都是基本的操作,关键就是2.
对于每个点维护这个点的轻儿子是否要反色。每次修改的时候直接区间修改即可。两条重链相连的轻边需要特判。路径的顶点到他父亲之间的边也需要特判。
每次计算答案的时候,链顶的颜色都要结合上父亲的轻儿子是否反色来计算。
代码
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 200003using namespace std;int point[N],v[N],nxt[N],deep[N],fa[N],size[N],son[N],belong[N];int pos[N],q[N],cnt,h[N];int tot,n,m,T;struct data{ int w,b,delta,rev;}tr[N*4];void add(int x,int y){ tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void dfs(int x,int f){ size[x]=1; son[x]=0; deep[x]=deep[f]+1; for (int i=point[x];i;i=nxt[i]){ if (v[i]==f) continue; fa[v[i]]=x; dfs(v[i],x); size[x]+=size[v[i]]; if (size[v[i]]>size[son[x]]) son[x]=v[i]; }}void dfs1(int x,int chain){ pos[x]=++cnt; q[cnt]=x; belong[x]=chain; if (!son[x]) return; dfs1(son[x],chain); for (int i=point[x];i;i=nxt[i]) if (v[i]!=son[x]&&v[i]!=fa[x]) dfs1(v[i],v[i]);}void update(data &now,data l,data r){ now.w=l.w+r.w; now.b=l.b+r.b;}void clear(int now){ tr[now].b=tr[now].w=tr[now].rev=tr[now].delta=0;}void build(int now,int l,int r){ clear(now); if (l==r) { tr[now].b=0; if (l!=1) tr[now].w=1; return; } int mid=(l+r)/2; build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(tr[now],tr[now<<1],tr[now<<1|1]);}void change(int now){ swap(tr[now].w,tr[now].b); tr[now].delta^=1;}void pushdown(int now){ if (tr[now].delta){ change(now<<1); change(now<<1|1); tr[now].delta=0; } if (tr[now].rev) { tr[now<<1].rev^=1; tr[now<<1|1].rev^=1; tr[now].rev=0; }}data query(int now,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return tr[now]; pushdown(now); int mid=(l+r)/2; data ans; bool pd=false; if (ll<=mid) ans=query(now<<1,l,mid,ll,rr),pd=true; if (rr>mid) { if (pd) update(ans,ans,query(now<<1|1,mid+1,r,ll,rr)); else ans=query(now<<1|1,mid+1,r,ll,rr); } return ans;}void qjchange(int now,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) { change(now); return; } int mid=(l+r)/2; pushdown(now); if (ll<=mid) qjchange(now<<1,l,mid,ll,rr); if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr); update(tr[now],tr[now<<1],tr[now<<1|1]);}void reverse(int now,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) { tr[now].rev^=1; return; } pushdown(now); int mid=(l+r)/2; if (ll<=mid) reverse(now<<1,l,mid,ll,rr); if (rr>mid) reverse(now<<1|1,mid+1,r,ll,rr); update(tr[now],tr[now<<1],tr[now<<1|1]);}void solve(int x,int y){ while (belong[x]!=belong[y]) { if (deep[belong[x]]<deep[belong[y]]) swap(x,y); qjchange(1,1,n,pos[belong[x]],pos[x]); x=fa[belong[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x==y) return; qjchange(1,1,n,pos[x]+1,pos[y]);}void paint(int x,int y){ bool pd=false; int t=0; while (belong[x]!=belong[y]){ if (deep[belong[x]]<deep[belong[y]]) swap(x,y); reverse(1,1,n,pos[belong[x]],pos[x]); if (son[x]) qjchange(1,1,n,pos[son[x]],pos[son[x]]); qjchange(1,1,n,pos[belong[x]],pos[belong[x]]); t=belong[x]; x=fa[belong[x]]; h[x]=t; } if (deep[x]>deep[y]) swap(x,y); reverse(1,1,n,pos[x],pos[y]); qjchange(1,1,n,pos[x],pos[x]); if (son[y]) qjchange(1,1,n,pos[son[y]],pos[son[y]]);}int find(int now,int l,int r,int x){ if (x==0) return 0; if (l==r) return tr[now].rev; int mid=(l+r)/2; pushdown(now); if (x<=mid) return find(now<<1,l,mid,x); else return find(now<<1|1,mid+1,r,x);}int calc(int x,int y){ int ans=0; while (belong[x]!=belong[y]) { if (deep[belong[x]]<deep[belong[y]]) swap(x,y); data t=query(1,1,n,pos[belong[x]],pos[x]); data t1=query(1,1,n,pos[belong[x]],pos[belong[x]]); int k=find(1,1,n,pos[fa[belong[x]]]); if (t1.b==1&&k) t.b--; if (t1.w==1&&k) t.b++; ans+=t.b; x=fa[belong[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x==y) return ans; data t=query(1,1,n,pos[x]+1,pos[y]); ans+=t.b; return ans;}int read(){ char c; int x=0; c=getchar(); while (c>'9'||c<'0') c=getchar(); while (c<='9'&&c>='0') x=x*10+c-'0',c=getchar(); return x;}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d",&T); while (T--){ tot=0; cnt=0; memset(point,0,sizeof(point)); scanf("%d",&n); for (int i=1;i<n;i++) { int x,y; x=read(); y=read(); add(x,y); } dfs(1,0); dfs1(1,1); build(1,1,n); scanf("%d",&m); for (int i=1;i<=m;i++) { //cout<<i<<endl; int opt,x,y; opt=read(); x=read(); y=read(); if (opt==1) solve(x,y); if (opt==2) paint(x,y); if (opt==3) printf("%d\n",calc(x,y)); } }}
阅读全文
0 0
- bzoj 3862: Little Devil I (树链剖分+线段树)
- 【BZOJ3862】Little Devil I【树链剖分】【线段树】
- hdu4897 Little Devil I(树链剖分+线段树)
- hdu 4897 Little Devil I(树链剖分+线段树)
- bzoj3862Little Devil I(树链剖分+线段树)
- hdu 4897 Little Devil I 树链剖分
- 【HDU】4987 Little Devil I 树链剖分
- bzoj3862: Little Devil I
- 【hdu 4897】Little Devil I
- hdu 4897 Little Devil I
- hdu 4897 Little Devil I 树剖(题如其名..)
- hdu_4897_Little Devil I(树链剖分)
- 【HDU 4897 多校联合】Little Devil I【树链刨分】
- BZOJ 2819 Nim (树链剖分+线段树)
- BZOJ 2243 染色(树链剖分+线段树)
- bzoj 4127: Abs(树链剖分+线段树)
- bzoj 4127: Abs(树链剖分+线段树)
- bzoj 1984(线段树+树链剖分)
- 单例模式
- ToolBar的再使用
- 常用工具(原理分析)
- python操作配置文件
- python解一元二次方程式分享
- bzoj 3862: Little Devil I (树链剖分+线段树)
- 公共数据库介绍~ProPublica
- sklearn特征提取方法学习
- 数学建模处理数据
- Java分页查询(真分页)
- TV Encoder MS7024
- 函数执行顺序 打印顺序
- 《Python数据分析与挖掘实战》笔记(五):数据建模
- C++面向对象思想(1):类的设计