[BZOJ3510]-首都-LCT维护重心
来源:互联网 发布:怎么mac的软件卸载不了 编辑:程序博客网 时间:2024/04/28 23:21
说在前面
终于知道…为什么自己惧怕写高sha端bi数据结构了
原来me的代码不仅自带大常数,还自带大长度
题目
BZOJ3510传送门
题目大意
有N个独立的节点,你需要维护接下来的M个操作,这M个操作分为如下三种:
1、
2、
3、
输入输出格式
输入格式:
第一行两个数字N , M,含义如题
接下来M行,每行描述一个操作,输入的格式如题
输出格式
对于每个Q操作和每个Xor操作,你需要输出一行一个整数回答询问
解法
看到这种有连边操作,并且保证是一棵树的,直接上LCT干死它
这道题的难点就是需要维护重心。
A操作很明显是Link操作。如果可以在A操作的时候顺便维护重心,那么询问操作就是O(1)的。
考虑如何维护,如果直接把两棵树连接在一起,显然是不太好维护的(需要让原来的重心在树里不断调整位置,但是LCT上只能访问链信息)。但是如果在一棵树上连接一个节点,重心要么保持不变,要么向新加节点的方向移动一个点(显然),这个是很方便维护的。
于是考虑启发式合并,每次合并两棵树的时候,把siz较小的树的节点逐个加入siz较大的树,并在加入的过程中维护重心。记录一棵树的siz可以用并查集实现。每次link操作之后,都在外面存一条实边(路径),这样在合并的时候就可以直接使用dfs访问一个联通块的所有节点。
关于时间复杂度,因为每次暴力的将较小的树加入较大的树时,siz至少会增加一倍(对于较小的树来说),那么较小树中的节点最多贡献
下面是自带大常数的代码
/************************************************************** Problem: 3510 User: Izumihanako Language: C++ Result: Accepted Time:2436 ms Memory:7072 kb****************************************************************/#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;int N , M , xsum , core[100005] , head[100005] , tp ;struct Union_set{ int fa[100005] , siz[100005] ; void init(){ for( int i = 1 ; i <= N ; i ++ ) fa[i] = i , siz[i] = 1 ; } int find( int x ){ if( fa[x] == x ) return x ; return fa[x] = find( fa[x] ) ; }}U ;struct Path{ int pre , to ;}p[200005] ;struct Node{ bool rev ; int rsiz , isiz , id ; Node *ch[2] , *fa ; void rever(){ swap( ch[0] , ch[1] ) ; rev ^= 1 ; } void update(){ rsiz = 1 ; if( ch[0] ) rsiz += ch[0]->rsiz + ch[0]->isiz ; if( ch[1] ) rsiz += ch[1]->rsiz + ch[1]->isiz ; } void pushdown(){ if( rev ){ if( ch[0] ) ch[0]->rever() ; if( ch[1] ) ch[1]->rever() ; rev = false ; } }} w[100005] ;void In( int t1 , int t2 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ;}bool isroot( Node *x ){ if( !x->fa ) return true ; if( x->fa->ch[0] != x && x->fa->ch[1] != x ) return true ; return false ;}void Rotate( Node *nd , const int &aim ){ Node *x = nd->ch[aim] ; if( nd->fa ){ if( nd->fa->ch[0] == nd ) nd->fa->ch[0] = x ; if( nd->fa->ch[1] == nd ) nd->fa->ch[1] = x ; } x->fa = nd->fa ; if( x->ch[aim^1] ){ x->ch[aim^1]->fa = nd ; } nd->ch[aim] = x->ch[aim^1] ; x->ch[aim^1] = nd , nd->fa = x ; nd->update() ; x->update() ;}int topp ;Node *sta[100005] ;void Splay( Node *nd ){ Node *tmp = nd ; topp = 0 ; for( ; !isroot( tmp ) ; tmp = tmp->fa ) sta[++topp] = tmp ; sta[++topp] = tmp ; for( ; topp ; topp -- ) sta[topp]->pushdown() ; while( !isroot( nd ) ){ Node *fa = nd->fa , *gdfa = fa->fa ; int pn = ( fa->ch[1] == nd ) , pf ; if( gdfa && !isroot( fa ) ){ pf = ( gdfa->ch[1] == fa ) ; if( pn == pf ){ Rotate( gdfa , pf ) ; Rotate( fa , pn ) ; } else { Rotate( fa , pn ) ; Rotate( gdfa , pf ) ; } } else Rotate( fa , pn ) ; }}void Access( Node *nd ){ Node *tmp = NULL ; while( nd ){ Splay( nd ) ; if( tmp ) nd->isiz -= tmp->rsiz + tmp->isiz ; if( nd->ch[1] ) nd->isiz += nd->ch[1]->rsiz + nd->ch[1]->isiz ; nd->ch[1] = tmp ; nd->update() ; tmp = nd ; nd = nd->fa ; }}void Makeroot( Node *x ){ Access( x ) ; Splay( x ) ; x->rever() ;}void Link( Node *y , Node *x ){// link y to x Makeroot( y ) ; Access( x ) ; Splay( x ) ; y->fa = x ; x->isiz += y->rsiz + y->isiz ; Node *G = ( w + core[U.find(x->id)] ) ; Makeroot( G ) ; Access( y ) ; Splay( G ) ;//Splay to update Node *tmp = G->ch[1] ; while( tmp->ch[0] ){ tmp = tmp->ch[0] ; tmp->pushdown() ; } Access( tmp ) ; Splay( G ) ;//Splay to Makeroot G and update G int tmpsiz2 = ( tmp->isiz + 1 ) * 2 , totsiz = G->isiz + G->rsiz ; if( tmpsiz2 > totsiz || ( tmpsiz2 == totsiz && tmp->id < G->id ) ){ core[ U.find(G->id) ] = tmp->id ; xsum = ( xsum ^ G->id ^ tmp->id ) ; }}void dfs( int u , int f ){ //reset u ,then Link u to f Node *nd = ( w + u ) ; nd->rev = false ; nd->rsiz = 1 ; nd->isiz = 0 ; nd->fa = nd->ch[0] = nd->ch[1] = NULL ; Link( nd , w + f ) ; for( int i = head[u] ; i ; i = p[i].pre ) if( p[i].to != f ) dfs( p[i].to , u ) ;}void solve(){ char opt[6] ; for( int i = 1 , a , b ; i <= M ; i ++ ){ scanf( "%s" , opt ) ; if( opt[0] == 'X' ) printf( "%d\n" , xsum ) ; else if( opt[0] == 'Q' ){ scanf( "%d" , &a ) ; printf( "%d\n" , core[ U.find(a) ] ) ; } else { scanf( "%d%d" , &a , &b ) ; int F_a = U.find( a ) , F_b = U.find( b ) ; if( U.siz[F_a] < U.siz[F_b] ) // a is bigger swap( a , b ) , swap( F_a , F_b ) ; xsum ^= core[F_b] ; U.siz[F_a] += U.siz[F_b] ; U.fa[F_b] = F_a ; dfs( b , a ) ; In( a , b ) ; In( b , a ) ; } }}void Program_initialize(){ U.init() ; for( int i = 1 ; i <= N ; i ++ ){ xsum ^= i ; core[i] = i ; w[i].id = i ; w[i].rev = false ; w[i].rsiz = 1 ; w[i].isiz = 0 ; w[i].fa = w[i].ch[0] = w[i].ch[1] = NULL ; }}int main(){ scanf( "%d%d" , &N , &M ) ; Program_initialize() ; solve() ;}