[bzoj3510]首都
来源:互联网 发布:淘宝上买中药材可靠吗 编辑:程序博客网 时间:2024/05/16 23:51
题目大意
一开始有n个结点,没有边。
有三种操作:将两个结点间连一条边,并且保证两个结点属不同联通块。询问一个联通块中所有点到其距离和最小的点。询问所有联通块中所有点到其距离和最小的点的异或和。
启发式合并
显然是一片森林,要求维护重心。
可以用启发式合并的思路,把小的合到大的里面,然后调整原本大的树里的重心,显然这个重心只会朝着小树方向调整,而且最多移动小树大小步。
然后需要用LCT来维护森林,并且要动态维护子树大小,还要兹瓷换根。怎么维护呢?
设siz[x]表示x的所有轻儿子子树大小和,那么想要获得x子树大小可以access(x)然后结果就是siz[x]+1。
spaly中维护size表示子树大小以及sum表示子树siz的和。
那么只需要在虚实交换的时候改变siz就行了。
也就是y是x一个儿子,y对x的影响是sum[y]+size[y]的(注意得保证y是其所在splay的根节点)
代码如下:
void real_empty(int x){ splay(x,0); if (!tree[x][1]) return; int y=suc(x); splay(y,x); siz[x]+=sum[y]+size[y]; pp[y]=x; tree[x][1]=0; father[y]=0; update(x);}void empty_real(int x,int y){ splay(x,0); splay(y,0); tree[x][1]=y; father[y]=x; pp[y]=0; siz[x]-=sum[y]+size[y]; update(x);}
那么因为siz不受实边影响,所以可以兹瓷换根操作。
实现方面:
1、每棵树用并查集维护,保存大小与重心。
2、注意考虑一颗树两个重心的情况!
3、将一条虚边变为实边必须保证y是x的儿子,所以access不能像以前一样大,每次要把x调整成splay中深度最小点,用kth操作解决。
4、因为换根所需要的翻转标记,所以求前驱、后继以及深度最小点均不能直接上(除非你顺便下传标记),最好都用kth操作解决,kth里注意下传标记。
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=100000+10;int fa[maxn],big[maxn],zx[maxn];int father[maxn],siz[maxn],size[maxn],sum[maxn],pp[maxn],tree[maxn][2],sta[maxn]; int tiaoshi[maxn];bool bz[maxn];int i,j,k,l,t,n,m,ans,top;char ch;int pd(int x){ return tree[father[x]][1]==x;}void update(int x){ size[x]=size[tree[x][0]]+size[tree[x][1]]+1; sum[x]=sum[tree[x][0]]+sum[tree[x][1]]+siz[x];}void rotate(int x){ int y=father[x],z=pd(x); father[x]=father[y]; if (father[y]) tree[father[y]][pd(y)]=x; tree[y][z]=tree[x][1-z]; if (tree[x][1-z]) father[tree[x][1-z]]=y; tree[x][1-z]=y; father[y]=x; update(y); update(x); if (pp[y]) pp[x]=pp[y],pp[y]=0;}void mark(int x){ if (!x) return; bz[x]^=1; swap(tree[x][0],tree[x][1]);}void down(int x){ if (bz[x]){ mark(tree[x][0]); mark(tree[x][1]); bz[x]=0; }}void remove(int x,int y){ top=0; while (x!=y){ sta[++top]=x; x=father[x]; } while (top){ down(sta[top]); top--; }}void splay(int x,int y){ remove(x,y); while (father[x]!=y){ if (father[father[x]]!=y) if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x); rotate(x); }}int getfa(int x){ return fa[x]?fa[x]=getfa(fa[x]):x;}int kth(int x,int y){ down(x); if (size[tree[x][0]]+1==y) return x; else if (size[tree[x][0]]>=y) return kth(tree[x][0],y); else return kth(tree[x][1],y-size[tree[x][0]]-1);}int pre(int x){ splay(x,0); return kth(tree[x][0],size[tree[x][0]]);}int suc(int x){ splay(x,0); return kth(tree[x][1],1);}void real_empty(int x){ splay(x,0); if (!tree[x][1]) return; int y=suc(x); splay(y,x); siz[x]+=sum[y]+size[y]; pp[y]=x; tree[x][1]=0; father[y]=0; update(x);}void empty_real(int x,int y){ splay(x,0); splay(y,0); tree[x][1]=y; father[y]=x; pp[y]=0; siz[x]-=sum[y]+size[y]; update(x);}void access(int x){ int y; real_empty(x); splay(x,0); x=kth(x,1); splay(x,0); while (pp[x]){ y=pp[x]; real_empty(y); empty_real(y,x); splay(x,0); x=kth(x,1); splay(x,0); }}void makeroot(int x){ access(x); splay(x,0); mark(x);}void merge(int x,int y){ int xx=getfa(x),yy=getfa(y); ans^=zx[xx]^zx[yy]; if (big[xx]<big[yy]||big[xx]==big[yy]&&x>y){ swap(x,y); swap(xx,yy); } makeroot(x); makeroot(y); splay(x,0); splay(y,0); siz[x]+=sum[y]+size[y]; update(x); pp[y]=x; big[xx]+=big[yy]; fa[yy]=xx; zx[yy]=0; int j=zx[xx],k; while (j!=x){ access(j); k=pre(j); if (big[xx]%2==1&&big[xx]-siz[j]-1<=big[xx]/2||big[xx]%2==0&&big[xx]-siz[j]-1<big[xx]/2||big[xx]%2==0&&big[xx]-siz[j]-1==big[xx]/2&&j<k) break; j=k; } zx[xx]=j; ans^=j;}char get(){ char ch=getchar(); while (ch!='A'&&ch!='Q'&&ch!='X') ch=getchar(); return ch;}int main(){ freopen("cap.in","r",stdin);freopen("cap.out","w",stdout); scanf("%d%d",&n,&m); fo(i,1,n) ans^=(zx[i]=i),big[i]=size[i]=1; fo(i,1,m){ ch=get(); if (ch=='A'){ scanf("%d%d",&j,&k); merge(j,k); } else if (ch=='Q'){ scanf("%d",&j); j=getfa(j); printf("%d\n",zx[j]); } else printf("%d\n",ans); }}
0 0
- bzoj3510: 首都
- [bzoj3510]首都
- BZOJ3510 首都
- [BZOJ3510]-首都-LCT维护重心
- [BZOJ3510][启发式合并][LCT维护子树信息]首都
- bzoj3510首都 LCT维护子树信息+启发式合并
- 各国首都列表
- 各国首都列表
- 首都人民拜拜啦!
- 感谢首都人民
- 首都师大 个人
- 海地首都太子港
- 啊~北京~~啊~首都~
- 首都航空客服电话
- 首都博物馆参观后
- 首都字母查找例子
- 首都查找例子(深搜)
- 中国朝代及首都
- m_hWnd和this指针
- ionic 使用Iconfont-阿里巴巴矢量图标库
- iOS QQ实现第三方登录以及遇到的问题
- python输入print直接打印中文乱码问题
- 估值两亿的自媒体“功夫财经”被永封
- [bzoj3510]首都
- css样式问题,table中的td值撑开了,样式变了
- 剑指offer11--让数组变成左边奇数右边偶数
- PHP学习笔记——文件操作
- 移动开发内存分类
- new和delete 基类指针指向继承类的对象时,delete的过程
- POJ-1287-Networking(最小生成树 普利姆)
- mysql 安装 和 配置 在 centos 7
- c++实现矩阵的余弦相似度