BZOJ4530: [Bjoi2014]大融合(LCT维护子树,线段树合并)
来源:互联网 发布:js点击图片全屏放大 编辑:程序博客网 时间:2024/05/16 03:12
传送门
题意:
给一个动态树,维护sze集合大小。
题解:
动态树。
LCT维护子树和的方法(不支持子树修改,其实实现起来也挺简单的):
对于维护这一类满足加减的信息,可以考虑在
LCT 的每个点分别维护出所有虚边和实边连向他和。
如果得到了维护,那么可以轻松在O(logn) 时间内完成询问。
考虑怎么维护:
首先Splay 不会改变虚边的性质,那么Splay 中直接动态调整实边的和就好了。
对于Access 操作,显然断开右儿子会导致虚实边切换,可以在维护的东西上简单加减就好了。不过需要注意的是,加减最好在当前点是其所在Splay 的根节点的时候才能加减,否则该点的和改变后其父节点的和也会相应改变(只有实父亲),还要向上update (虚父亲不用更新是因为Access 操作会一路向上走,总会更新到虚父亲的)。
对于Link 操作,直接连边也会导致一样的错误,那么先将两边的点都置为根节点就好了。
对于每组查询操作,先将查询点Access ,此时其虚子树和包含了其所有子树,可以加上自己的信息而得到答案。
关于维护最大最小值也可以用类似的方法。不过需要注意的是不能简单的加减,容易想到增加一个
- Code
#include<bits/stdc++.h>using namespace std;inline int rd(){ char ch=getchar();int i=0,f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();} return i*f;}inline void W(long long x){ static int buf[50]; if(!x){putchar('0');return;} if(x<0){putchar('-');x=-x;} while(x){buf[++buf[0]]=x%10,x/=10;} while(buf[0]){putchar(buf[buf[0]--]+'0');}}const int Maxn=1e5+50;int n,m;struct node{ node *lc,*rc,*fa; int sze_v,sze_t,revtag; node():lc(NULL),rc(NULL),fa(NULL),sze_t(1){} inline void rev();inline void upt();inline void pd();}Pool[Maxn],*pool=Pool;inline void node::upt(){sze_t=(lc?lc->sze_t+lc->sze_v:0)+(rc?rc->sze_t+rc->sze_v:0)+1;}inline void node::rev(){revtag^=1;swap(lc,rc);}inline bool isroot(node *x){return !x->fa||(x->fa->lc!=x&&x->fa->rc!=x);}inline bool which(node *x){return x->fa->lc==x;}inline void node::pd(){ if(!isroot(this))fa->pd(); if(revtag){ if(lc)lc->rev();if(rc)rc->rev(); revtag=0; }}inline void rotate(node *x){ node *y=x->fa,*z=y->fa; if(!isroot(y))((z->lc==y)?z->lc:z->rc)=x; x->fa=z;y->fa=x; if(y->lc==x){ node *b=x->rc; x->rc=y;y->lc=b; if(b)b->fa=y; }else{ node *b=x->lc; x->lc=y;y->rc=b; if(b)b->fa=y; } y->upt();x->upt();}inline void splay(node *x){ x->pd(); while(!isroot(x)){ node *y=x->fa; if(!isroot(y)){ (which(y)^which(x))?(rotate(x)):(rotate(y)); }rotate(x); }}inline void access(node *x){ for(node *t=NULL;x;t=x,x=x->fa){ splay(x);int rc_sze=(x->rc)?(x->rc->sze_t+x->rc->sze_v):0; x->sze_t-=rc_sze;x->sze_v+=rc_sze; x->rc=t;rc_sze=(x->rc)?(x->rc->sze_t+x->rc->sze_v):0; x->sze_t+=rc_sze;x->sze_v-=rc_sze; }}inline void makeroot(node *x){ access(x);splay(x);x->rev();}inline void link(node *x,node *y){ makeroot(x);makeroot(y);x->fa=y; y->sze_v+=(x->sze_v+x->sze_t);}inline void query(node *x,node *y){ makeroot(x);int sze1=x->sze_t+x->sze_v; access(y);int sze2=y->sze_v+1; W(1ll*(sze1-sze2)*sze2);putchar('\n');}int main(){ n=rd(),m=rd(); for(int i=1;i<=m;i++){ static char ch[2]; scanf("%s",ch+1); (ch[1]=='A')?(link(pool+rd(),pool+rd())):(query(pool+rd(),pool+rd())); }}
线段树合并一样可以处理,考虑先把原树的关系处理出来,对于当前联通快,按照
#include<bits/stdc++.h>using namespace std;struct IO{ streambuf *ib,*ob; int buf[50]; inline void init() { ios::sync_with_stdio(false); cin.tie(NULL);cout.tie(NULL); ib=cin.rdbuf();ob=cout.rdbuf(); } inline int read() { char ch=ib->sbumpc();int i=0,f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();} while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();} return i*f; } inline void W(long long x) { if(!x){ob->sputc('0');ob->sputc('\n');return;} if(x<0){ob->sputc('-');x=-x;} while(x){buf[++buf[0]]=x%10;x/=10;} while(buf[0]){ob->sputc(buf[buf[0]--]+'0');} ob->sputc('\n'); }}io;const int Maxn=1e5+50;int n,m,ecnt,rt[Maxn],dfn[Maxn],dep[Maxn],anc[Maxn],ind,out[Maxn],tot;int sze[Maxn*20],lc[Maxn*20],rc[Maxn*20];struct Q{ int k,x,y;}q[Maxn];vector<int>edge[Maxn];inline void dfs(int now,int f){ dfn[now]=++ind;dep[now]=dep[f]+1; for(int e=edge[now].size()-1;e>=0;e--) { int v=edge[now][e]; if(v==f)continue; dfs(v,now); } out[now]=ind;}inline void update(int now){ sze[now]=sze[lc[now]]+sze[rc[now]];}inline int getf(int now){ return (anc[now]==now)?(now):(anc[now]=getf(anc[now]));}inline void insert(int now,int l,int r,int pos){ if(l==r) { sze[now]=1; return; } int mid=(l+r)>>1; if(pos<=mid)insert(lc[now]=++tot,l,mid,pos); else insert(rc[now]=++tot,mid+1,r,pos); update(now);}inline int merge(int x,int y){ if(!y)return x; if(!x)return y; sze[x]+=sze[y]; lc[x]=merge(lc[x],lc[y]); rc[x]=merge(rc[x],rc[y]); return x;}inline int query(int now,int l,int r,int L,int R){ if(L<=l&&r<=R)return sze[now]; int mid=(l+r)>>1; int res=0; if(L<=mid&&lc[now])res+=query(lc[now],l,mid,L,R); if(R>mid&&rc[now])res+=query(rc[now],mid+1,r,L,R); return res;}int main(){ io.init();n=io.read(),m=io.read(); for(int i=1;i<=n;i++)anc[i]=i; for(int i=1;i<=m;i++) { static char ch[3]; cin>>(ch+1); q[i].k=((ch[1]=='A')?1:2),q[i].x=io.read(),q[i].y=io.read(); if(q[i].k==1) { edge[q[i].x].push_back(q[i].y); edge[q[i].y].push_back(q[i].x); } } for(int i=1;i<=n;i++)if(!dfn[i])dfs(i,0); for(int i=1;i<=n;i++) { rt[i]=++tot; insert(rt[i],1,n,dfn[i]); } for(int i=1;i<=m;i++) { if(dep[q[i].x]>dep[q[i].y])swap(q[i].x,q[i].y); if(q[i].k==1) { rt[getf(q[i].x)]=merge(rt[getf(q[i].x)],rt[getf(q[i].y)]); anc[getf(q[i].y)]=anc[q[i].x]; } else { int k=getf(q[i].y); int v=query(rt[k],1,n,dfn[q[i].y],out[q[i].y]); io.W(1ll*(sze[rt[k]]-v)*v); } }}
阅读全文
0 0
- BZOJ4530: [Bjoi2014]大融合(LCT维护子树,线段树合并)
- bzoj4530 [Bjoi2014]大融合(LCT维护子树大小)
- bzoj4530 [Bjoi2014]大融合 (LCT维护子树信息)
- [BZOJ4530][Bjoi2014][LCT维护子树信息]大融合
- [BZOJ4530]-大融合-LCT维护子树信息
- 【BJOI2014】大融合 LCT维护子树信息
- 【bzoj4530】[Bjoi2014]大融合 并查集+线段树合并
- JZOJ 3766【BJOI2014】大融合(lct维护子树大小)
- BZOJ4530 BJOI 2014 大融合 LCT维护子树信息
- BZOJ 4530 [Bjoi2014]大融合 LCT维护子树信息
- bzoj 4530: [Bjoi2014]大融合 lct维护子树信息
- [BZOJ]4530 [BJOI2014] 大融合 LCT维护子树信息
- BZOJ 4530: [Bjoi2014]大融合 lct维护子树信息
- 【bzoj4530】【BJOI2014】【大融合】【dfs序+线段树合并+并查集】
- bzoj4530[Bjoi2014]大融合 线段树合并+dfs序+并查集
- bzoj4530: [Bjoi2014]大融合 //线段树分治+并查集
- BZOJ4530 [Bjoi2014]大融合
- [BZOJ4530][Bjoi2014]大融合(树链剖分+并查集)
- 判断多边形凹凸(计算几何基础)
- HTML链接
- 资讯精选 | 开源大数据周刊-第63期
- 十六进制颜色值
- ZOJ-3453:Doraemon's Sweet Bullet
- BZOJ4530: [Bjoi2014]大融合(LCT维护子树,线段树合并)
- pat 1032. 挖掘机技术哪家强(20)
- 运用JQuery的AJAX实现excel文件下载
- Unity-Transform实例-小飞机
- Effective C++ 条款二解读
- Node.js机制及原理理解初步
- js-tab切换处理
- Win10系统字体
- Java集合类详解