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 }
View Code

 

posted @ 2018-08-16 10:20  Schenker  阅读(191)  评论(0编辑  收藏  举报