zoukankan      html  css  js  c++  java
  • 【Luogu4299】首都

    BZOJ权限题。
    洛谷

    题目描述

    在X星球上有N个国家,每个国家占据着X星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。

    X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖。A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路。

    同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。

    现在告诉你发生在X星球的战事,需要你处理一些关于国家首都的信息,具体地,有如下3种信息需要处理:

    A x y:表示某两个国家发生战乱,战胜国选择了x城市和y城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。
    Q x:询问当前编号为x的城市所在国家的首都。
    Xor:询问当前所有国家首都编号的异或和。
    

    Sol

    就是让你动态维护重心 , 但只有加边操作。

    重心的一个性质 , 当加入一个叶子节点后 , 重心最多移动一条边的距离。
    而判断一个点是否是重心 , 只需要判断它的各儿子的子树大小是否超过整棵树大小一半即可。
    所以有一个暴力做法 , 启发式合并 , 然后判断重心是否移动即可。
    复杂度(O(nlog^2n))

    更加优秀的做法:
    重心还有个性质 , 合并两棵树 , 新的重心一定在原来两个重心的路径上 。
    那么我们用 (LCT) 把路径抠出来 , 重心的位置是可以二分出来的。
    具体来说 , 我们在 (Splay) 上走 , 每次把两边的 (size) 维护好然后判断最大子树大小就行了
    注意这里并不需要关心虚子树大小 , 简单来理解就是重心会往大的子树方向动 , 但是合并两棵子树后重心在路径上 , 所以不用关心原来的子树。严格一点分析 , 由于原来那些子树大小不超过原来大小的一半 , 自然不会超过现在大小的一半 。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>inline void init(T&x){
    	x=0;char ch=getchar();bool t=0;
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    	if(t) x=-x;
    }
    const int N(1e5+10);
    int n,m;
    #define ls son[0]
    #define rs son[1]
    #define __ NULL
    #define get_son(a) (a->fa->rs==a)
    #define get(a,b,c) (a? a->b:c)
    #define IS(a) (a&&(!a->fa||(a->fa->son[get_son(a)]!=a)))
    
    struct node{
    	node*son[2],*fa;int size,cnt;bool rev;
    	node(){ls=rs=fa=__,size=cnt=1;rev=0;}
    }T[N],*stk[N];int top=0;
    inline void update(node*p){if(!p)return;p->size=get(p->ls,size,0)+get(p->rs,size,0)+p->cnt;}
    inline void rotate(node*p){
    	int k=get_son(p);node*q=p->fa,*gp=p->fa->fa;
    	q->son[k]=p->son[k^1];
    	if(p->son[k^1]) p->son[k^1]->fa=q;
    	if(!IS(q)) gp->son[get_son(q)]=p;
    	p->fa=gp,q->fa=p,p->son[k^1]=q;
    	return update(q);
    }
    inline void push_down(node*p){
    	if(!p||!p->rev)return;swap(p->ls,p->rs);p->rev=0;
    	if(p->ls)p->ls->rev^=1;if(p->rs) p->rs->rev^=1;
    	return;
    }
    inline void Push(node*p){
    	stk[top=1]=p;while(!IS(p)) p=p->fa,stk[++top]=p;
    	while(top) push_down(stk[top--]);return;
    }
    inline void Splay(node*p){
    	if(!p)return;Push(p);
    	for(;!IS(p);rotate(p)) if(IS(p->fa)) continue;else get_son(p->fa)==get_son(p)? rotate(p->fa):rotate(p);
    	return update(p);
    }
    inline void access(node*p){node*pre=__;for(;p;pre=p,p=p->fa)Splay(p),p->cnt+=get(p->rs,size,0)-get(pre,size,0),p->rs=pre,update(p);}
    inline void make_root(node*p){access(p);Splay(p);p->rev^=1;}
    inline void split(node*p,node*q){make_root(p),access(q),Splay(q);return;}
    inline void link(node*p,node*q){split(p,q);p->fa=q;q->cnt+=p->size,update(q);return;}
    inline void cut(node*p,node*q){split(p,q);if(q->ls==p) p->fa=q->ls=__,update(q);return;}
    inline node* Find(node*p){access(p);Splay(p);while(p->ls)p=p->ls;return p;}
    inline int WP(int u){return (int)(Find(&T[u])-T);}
    #define ID(a) ((a)-T)
    int Xor,TOT;
    inline void Solve(node*p,node*q) {
    	split(p,q);node*u=q;node*Ne=__;
    	int ban=TOT>>1;
    	int suml=0,sumr=0;
    	int nowl,nowr;
    	while(u) {
    		push_down(u);
    		node*L=u->ls,*R=u->rs;
    		nowl=suml+get(L,size,0),nowr=sumr+get(R,size,0);
    		if(nowl<=ban&&nowr<=ban) {
    			if(TOT&1) {Ne=u;break;}
    			else if((!Ne)||ID(Ne)>ID(u)) Ne=u;
    		}
    		if(nowl>=nowr) sumr+=get(R,size,0)+u->cnt,u=L;
    		else           suml+=get(L,size,0)+u->cnt,u=R;
    	}
    	make_root(Ne);Xor^=ID(Ne);
    }
    int main()
    {
    	init(n),init(m);
    	int u,v;for(int i=1;i<=n;++i) Xor^=i;
    	for(int i=1;i<=m;++i) {
    		char ch=getchar();while(ch!='A'&&ch!='Q'&&ch!='X') ch=getchar();
    		if(ch=='A') {
    			init(u),init(v);
    			int x=WP(u),y=WP(v);
    			Splay(&T[x]),Splay(&T[y]);
    			TOT=T[x].size+T[y].size;
    			Xor^=x^y;link(&T[u],&T[v]);
    			Solve(&T[x],&T[y]);
    		}
    		else if(ch=='Q') {init(u);printf("%d
    ",WP(u));}
    		else if(ch=='X') printf("%d
    ",Xor);
    	}
    }
    
    
  • 相关阅读:
    【matlab】学习笔记 2脚本编写
    【matlab】学习笔记 1 入门简单操作
    【matlab】学习笔记 3 函数编写
    MySQL学习笔记
    数据库连接-----MySQL -> JDBC
    leetcode——Mysql数据库查询题目
    不同单词个数统计
    初始化二维数组
    JS基本变量类型和对象杂谈
    LeetCode Clone Graph
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/10428604.html
Copyright © 2011-2022 走看看