smoj2017(树链剖分+线段树/LCT)
来源:互联网 发布:绿岸网络2017 编辑:程序博客网 时间:2024/06/03 13:19
还是在比赛时虐我的题,我当时做到一半回家了。回到家之后只会打暴力,结果看到米娜都ac了,顿时鸡都不想吃了。没想到是n方过十万…
题意:有一棵n个点的萌萌的黑白树,一开始结点都是黑的。搞了m件事情,每件事情要么可以变一个点的颜色,或者询问一个点和它同色的连通块的大小。
这个问题完全可以放在一个图上。之所以在一棵树上,因为树有顺序,每个点不必维护整个连通块的信息,只需要维护子树信息就可以了。
0表示黑,1表示白
每个点维护两个信息,ans0和ans1。分别表示当这个点是黑色/白色时,该点和它的子树构成的黑色/白色的连通块大小。(也许经历了所有的悲伤,这个就能想出来吧)
然后先考虑有这两个信息,怎么得到询问的答案。经过小小的分析,是这样的
假设询问点x,就不断的往父亲上跳,找到距离它最远的,与它路径上的点都是同色的祖先p。p的答案就是询问的答案。
考虑修改点x,x原来的颜色是col,同样找到那个祖先p,由fa[x]到p的路径上的ans[col]-=(x的ans[col])。再改变x的颜色,再找p,由fa[x]到p的路径上的ans[col^1]+=(x的ans[col^1])。
这个链修改,单点询问,可用树链剖分+线段树实现。至于第一个不同色的点,在线段树上维护这个信息就可以了。
觉得树剖很愚蠢,追求复杂度的同学也可以用LCT模拟上述过程。(然而并没有Link和Cut)
其实这题就是一棵裸的LCT。每个点都多开两个点,分别像黑色的儿子和白色的儿子连边。改颜色就模拟来Link和Cut。答案就是连通块大小。LCT不会维护连通块大小的?点这里
花俏的LCT
#include <iostream>#include <fstream>#include <algorithm>#include <cmath>#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define mmst(a, b) memset(a, b, sizeof(a))#define mmcp(a, b) memcpy(a, b, sizeof(b))#define imax(a, b) (((a)>(b)) ? (a) : (b))typedef long long LL;const int N=200200;void read(int &hy){ hy=0; char cc=getchar(); while(cc>'9'||cc<'0') cc=getchar(); while(cc>='0'&&cc<='9') { hy=(hy<<3)+(hy<<1)+cc-'0'; cc=getchar(); }}int n,q;int to[N],nex[N],head[N],cnt;int fa[N],siz[N];void add(int u,int v){ to[++cnt]=v; nex[cnt]=head[u]; head[u]=cnt;}void dfs(int x){ siz[x]=1; for(int h=head[x];h;h=nex[h]) if(to[h]!=fa[x]) { fa[to[h]]=x; dfs(to[h]); siz[x]+=siz[to[h]]; }}struct tree{ tree *c[2],*f,*pp; bool col,k[2]; int ad[2],ans[2]; int d(){return f->c[1]==this;} void sc(tree *x,int d){(c[d]=x)->f=this;}}nil[N],*ro[N];void up(tree *x){ x->k[0]=x->k[1]=x->col; if(x->c[0]!=nil) { x->k[0]=x->k[0] | x->c[0]->k[0]; x->k[1]=x->k[1] & x->c[0]->k[1]; } if(x->c[1]!=nil) { x->k[0]=x->k[0] | x->c[1]->k[0]; x->k[1]=x->k[1] & x->c[1]->k[1]; }}void down(tree *x){ for(int i=0;i<2;i++) { x->c[0]->ad[i]+=x->ad[i]; x->c[0]->ans[i]+=x->ad[i]; x->c[1]->ad[i]+=x->ad[i]; x->c[1]->ans[i]+=x->ad[i]; x->ad[i]=0; }}void work(tree *x){ if(x->f!=nil) work(x->f); down(x);}void zig(tree *x){ tree *y=x->f; int d=x->d(); y->sc(x->c[!d],d); if(y->f==nil) x->f=nil; else y->f->sc(x,y->d()); x->sc(y,!d); x->pp=y->pp; y->pp=nil; up(y); up(x);}void splay(tree *x){ work(x); for(tree *y;x->f!=nil;) { y=x->f; if(y->f!=nil) (x->d() ^ y->d()) ? zig(x) : zig(y); zig(x); }} void Access(tree *x){ tree *y=nil; while(x!=nil) { splay(x); if(x->c[1]!=nil) { x->c[1]->f=nil; x->c[1]->pp=x; } x->c[1]=y; if(y!=nil) y->f=x; y->pp=nil; up(x); y=x; x=x->pp; }}tree *find(tree *x){ Access(x); splay(x); int co=x->col; tree *y; while(x!=nil) { if((x->c[1]->k[co]==co||x->c[1]==nil)&&x->col==co) { y=x; x=x->c[0]; } else x=x->c[1]; } splay(y); return y;}int main(){ nil->c[0]=nil->c[1]=nil->f=nil->pp=nil; cin>>n; for(int i=1;i<=n;i++) { nil[i]=nil[0]; ro[i]=&nil[i]; } for(int i=1;i<n;i++) { int u,v; read(u); read(v); add(u,v); add(v,u); } dfs(1); for(int i=1;i<=n;i++) ro[i]->ans[0]=siz[i],ro[i]->ans[1]=1; for(int i=2;i<=n;i++) ro[i]->pp=ro[fa[i]]; cin>>q; while(q--) { int ops,x; read(ops); read(x); tree *hy=find(ro[x]); int co=ro[x]->col; if(!ops) printf("%d\n",hy->ans[co]); else { int si=ro[x]->ans[co]; int tu=si; ro[x]->ans[co]+=si; hy->ans[co]-=si; hy->c[1]->ans[co]-=si; hy->c[1]->ad[co]-=si; if(fa[hy-nil]) ro[fa[hy-nil]]->ans[co]-=si; co^=1; si=ro[x]->ans[co]; splay(ro[x]); ro[x]->col^=1; up(ro[x]); ro[x]->ans[co]=0; hy=find(ro[x]); hy->ans[co]+=si; hy->c[1]->ans[co]+=si; hy->c[1]->ad[co]+=si; if(fa[hy-nil]) ro[fa[hy-nil]]->ans[co]+=si; } } return 0;}
阅读全文
0 0
- smoj2017(树链剖分+线段树/LCT)
- BZOJ 4817 [LCT][线段树][树链剖分]
- Sunshine’s city(lct+线段树)
- 动态树LCT||树链剖分+线段树(SPOJ QTREE3 - Query on a tree again!)
- 【校内互侧】Sunshine’s city (lct+线段树)
- BZOJ3514(LCT+可持久化线段树)
- 【Codechef】【Gangsters of Treeland】Lct 线段树
- bzoj3779 lct+线段树+dfs序
- Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)
- BZOJ3514:Codechef MARCH14 GERALD07加强版 (LCT+可持久化线段树)
- BZOJ4530: [Bjoi2014]大融合(LCT维护子树,线段树合并)
- BZOJ 3779 重组病毒 LCT+线段树维护DFS序
- [LCT 线段树 dfs序] BZOJ 3779 重组病毒
- 【XSY2528】道路建设 LCT 可持久化线段树
- 动态树LCT(SPOJ375)
- BZOJ4025(LCT+LCT+LinkCutTree)
- poj 3237 Tree 树链剖分 动态树 LCT
- 【bzoj1036】树的统计 树链剖分/LCT
- 【算法分析与设计】【第三周】215. Kth Largest Element in an Array
- CTS 环境搭建及注意事项
- 图论——最小生成树
- bzoj 5043: 密码破译
- Prime Ring Problem
- smoj2017(树链剖分+线段树/LCT)
- 计蒜客 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 M. Frequent Subsets Problem (位压缩)
- memset的一个错误用法
- Kaggle学习之Machine Learning from Disaster(1)
- git
- c++ 虚函数
- 每天一篇Makefile(一)
- 安装WIN10 准备就绪半小时
- 每日掌握一个Linux命令 之 检测系统资源化 vmstat