[BZOJ3510]-首都-LCT维护重心

来源:互联网 发布:怎么mac的软件卸载不了 编辑:程序博客网 时间:2024/04/28 23:21

说在前面

终于知道…为什么自己惧怕写高sha端bi数据结构了
原来me的代码不仅自带大常数,还自带大长度


题目

BZOJ3510传送门

题目大意

有N个独立的节点,你需要维护接下来的M个操作,这M个操作分为如下三种:
1、A x y:在x和y之间连一条边,保证x和y在该操作前不联通
2、Q x:询问x所在联通块的重心
3、Xor:询问所有联通块的重心的异或和

输入输出格式

输入格式:
第一行两个数字N , M,含义如题
接下来M行,每行描述一个操作,输入的格式如题

输出格式

对于每个Q操作和每个Xor操作,你需要输出一行一个整数回答询问


解法

看到这种有连边操作,并且保证是一棵树的,直接上LCT干死它

这道题的难点就是需要维护重心。
A操作很明显是Link操作。如果可以在A操作的时候顺便维护重心,那么询问操作就是O(1)的。
考虑如何维护,如果直接把两棵树连接在一起,显然是不太好维护的(需要让原来的重心在树里不断调整位置,但是LCT上只能访问链信息)。但是如果在一棵树上连接一个节点,重心要么保持不变,要么向新加节点的方向移动一个点(显然),这个是很方便维护的。
于是考虑启发式合并,每次合并两棵树的时候,把siz较小的树的节点逐个加入siz较大的树,并在加入的过程中维护重心。记录一棵树的siz可以用并查集实现。每次link操作之后,都在外面存一条实边(路径),这样在合并的时候就可以直接使用dfs访问一个联通块的所有节点。

关于时间复杂度,因为每次暴力的将较小的树加入较大的树时,siz至少会增加一倍(对于较小的树来说),那么较小树中的节点最多贡献log(N)次合并复杂度,而每次合并都是log(N)的,因此单个点合并复杂度最多log(N)2,所以总复杂度Nlog(N)2


下面是自带大常数的代码

/**************************************************************    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() ;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 五虎汤组成 五虎网 腹黑蛇殿斗萌妃 五蛇酒是哪五蛇 我是什么命 命相查询 怎么算什么命 查什么命 什么命怎么算 怎么查什么命 查自己是什么命 怎样知道自己是什么命 怎么查自己是什么命 怎么知道自己是什么命 属命查询 高兴花园五街坊 五建新街坊 安全生产五要素 保险五要素 领导力五要素 八要素五步工作内容 安全生产五要素包括 螺纹的五要素 八要素五步工作法的具体内容 团队管理五要素是什么 圆曲线的五个要素 沟通五要素 五要素 一个团队必备的五个基本要素 安全管理基本原理的五个要素 超觉英语学习法 上海五角场 上海五角场酒店 五角场镇 五角场租房 杨浦区五角场 上海杨浦区五角场 上海五角场凯悦酒店 五角场有什么好玩的 五边形有几个角 双角形子宫