说在前面
终于知道…为什么自己惧怕写高sha端bi数据结构了
原来me的代码不仅自带大常数,还自带大长度
题目
题目大意
有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() ;
}