bzoj2049 Cave 洞穴勘测 lct
这里比上次多了几个操作。
1. make_root(u)
换根节点, 先access(u), 再splay(u),将u移动到splay树的最顶上, 现在这棵splay对于root来说 只有左子树上有东西, 右子树上没有东西, 那么交换一下左右子树, 再打个标记, 这样就变成了左子树没东西,右子树上有东西, 这样 u就变成根节点了。
2.link(u,v)
就是将 u 和 v 连在一起,我本来想的是直接把 Access(u), Splay(u), 再pre[u] = v就好了, 但是这样是不对的,
假设 u -> x, z -> x , x是原来lct u 的根, 现在我们只操作 Access(u), Splay(u) 在把 pre[u] = v, 这样看似连起来了, 但是判断z 和 v 的连通性的时候不能保证联通,我们要先转换根节点, 把 u 的lct变成一 u 为根的树, 然后在pre[u] = v, 就把2个树联通起来了。
3.cut(u,v)
我本来的想法是 直接access(v) 然后 pre[v]等于0就好了。
但是,你无法保证我们是pre[u] = v 还是 pre[v] = u。
并且假设 在link的时候 pre[u] = v,你执行完access 之后 pre[u] 不一定等于 v 因为是一颗splay 所以就算你再Splay(u)之后 你的 左儿子也不一定就是v。 由于splay的性质。
所以 我们需要makeroot(v) 再access(u) splay(u) 现在 在 splay u上面只有2个节点, u 和 v, 所以我们现在就确保了 u的左子树一定是v。
4 Rev(u)
这个函数出现在了 Splay的地方, 原因就是 你可能前面的某个节点执行了翻转, 由于lazy的原因, 我们需要把标记从上往下传, 所以我们就需要先找到这棵splay的根, 然后再一步一步把需要下穿的lazy传过来。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define lch(x) tr[x].son[0] 12 #define rch(x) tr[x].son[1] 13 #define max3(a,b,c) max(a,max(b,c)) 14 #define min3(a,b,c) min(a,min(b,c)) 15 typedef pair<int,int> pll; 16 const int inf = 0x3f3f3f3f; 17 const LL INF = 0x3f3f3f3f3f3f3f3f; 18 const LL mod = (int)1e9+7; 19 const int N = 1e5 + 100; 20 struct Node{ 21 int rev, rt; 22 int son[2], pre; 23 void init(){ 24 rt = 1; rev = pre = son[0] = son[1] = 0; 25 } 26 }tr[N]; 27 void Push_Rev(int x){ 28 if(!x) return ; 29 swap(lch(x), rch(x)); 30 tr[x].rev ^= 1; 31 } 32 void Push_Up(int x){ 33 34 } 35 void Push_Down(int x){ 36 if(tr[x].rev){ 37 tr[x].rev = 0; 38 Push_Rev(lch(x)); 39 Push_Rev(rch(x)); 40 } 41 } 42 void Rev(int x){ 43 if(!tr[x].rt) Rev(tr[x].pre); 44 Push_Down(x); 45 } 46 47 void rotate(int x){ 48 if(tr[x].rt) return; 49 int y = tr[x].pre, z = tr[y].pre; 50 int k = (rch(y) == x); 51 tr[y].son[k] = tr[x].son[k^1]; 52 tr[tr[y].son[k]].pre = y; 53 tr[x].son[k^1] = y; 54 tr[y].pre = x; 55 tr[x].pre = z; 56 if(tr[y].rt) tr[y].rt = 0, tr[x].rt = 1; 57 else tr[z].son[rch(z) == y] = x; 58 Push_Up(y); 59 } 60 void Splay(int x){ 61 Rev(x); 62 while(!tr[x].rt){ 63 int y = tr[x].pre, z = tr[y].pre; 64 if(!tr[y].rt){ 65 if(( x == rch(y) ) != (y == rch(z))) rotate(y); 66 else rotate(x); 67 } 68 rotate(x); 69 } 70 Push_Up(x); 71 } 72 void Access(int x){ 73 int y = 0; 74 do{ 75 Splay(x); 76 tr[rch(x)].rt = 1; 77 rch(x) = y; 78 tr[y].rt = 0; 79 Push_Up(x); 80 y = x; 81 x = tr[x].pre; 82 }while(x); 83 } 84 void Make_rt(int x){ 85 Access(x); 86 Splay(x); 87 Push_Rev(x); 88 } 89 void link(int u, int v){ 90 Make_rt(u); 91 tr[u].pre = v; 92 } 93 void cut(int u, int v){ 94 Make_rt(u); 95 Access(v); 96 Splay(v); 97 tr[lch(v)].pre = 0; 98 tr[lch(v)].rt = 1; 99 tr[v].pre = 0; 100 lch(v) = 0; 101 } 102 bool judge(int u, int v){ 103 while(tr[u].pre) u = tr[u].pre; 104 while(tr[v].pre) v = tr[v].pre; 105 return u == v; 106 } 107 int n, m, u, v; 108 char op[50]; 109 int main(){ 110 scanf("%d%d", &n, &m); 111 for(int i = 1; i <= n; i++){ 112 tr[i].init(); 113 } 114 115 while(m--){ 116 scanf("%s%d%d", op, &u, &v); 117 if(op[0] == 'Q'){ 118 if(judge(u,v)) puts("Yes"); 119 else puts("No"); 120 } 121 else if(op[0] == 'C') link(u,v); 122 else cut(u,v); 123 } 124 return 0; 125 }