HDU 6394 Tree 分块 || lct

Tree

题意: 给你一颗树, 每一个节点都有一个权值, 如果一个石头落在某个节点上, 他就会往上跳这个的点的权值步。 现在有2种操作, 1 把一个石头放在 x 的位置 询问有跳几次才跳出这棵树, 2 修改某个节点的权值。

解法:树上分块, 用dfs分好块之后。 对于每一块都处理出如果石头落在某个位置之后他跳出这个块之后的位置和次数。

每次更新都自己这一块的所有子节点, 然后找第k个父亲的时候用倍增优化。 

对于每次询问都跳到0号点之后,返回所经过的次数。

我们可以对属于同一块内的节点重新建立边, 因为我们在更新的时候不会直接访问到别的块的点, 所以重新建立边,避免遍历不需要的边(快了200ms)。

代码:

  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 max3(a,b,c) max(a,max(b,c))
 12 #define min3(a,b,c) min(a,min(b,c))
 13 typedef pair<int,int> pll;
 14 const int inf = 0x3f3f3f3f;
 15 const LL INF = 0x3f3f3f3f3f3f3f3f;
 16 const LL mod =  (int)1e9+7;
 17 const int N = 1e5 + 100;
 18 int n, m, b;
 19 int head[N], to[N], nt[N]; /// E1
 20 int head2[N], to2[N], nt2[N]; /// E2
 21 int Stack[N], belong[N];
 22 int jump[N], tto[N], cnt[N];
 23 int tot, top, type, tot2;
 24 int anc[N][20];
 25 inline void add2(int u, int v){
 26     to2[tot2] = v;
 27     nt2[tot2] = head2[u];
 28     head2[u] = tot2++;
 29 }
 30 inline void add(int u, int v){
 31     to[tot] = v;
 32     nt[tot] = head[u];
 33     head[u] = tot++;
 34 }
 35 void dfs(int u){
 36     int now = top, v;
 37     for(int i = head[u]; ~i; i = nt[i]){
 38         v = to[i];
 39         anc[v][0] = u;
 40         for(int i = 1; i < 20; i++)
 41             anc[v][i] = anc[anc[v][i-1]][i-1];
 42         dfs(v);
 43         if(top-now >= b){
 44             ++type;
 45             while(top!=now){
 46                 belong[Stack[top--]] = type;
 47             }
 48         }
 49     }
 50     Stack[++top] = u;
 51 }
 52 inline int Find(int x, int k){
 53     for(int i = 19; i >= 0; i--)
 54         if((k>>i)&1) x = anc[x][i];
 55     return x;
 56 }
 57 inline void Update(int x){
 58     int z = jump[x];
 59     if(belong[z] == belong[x]){
 60         tto[x] = tto[z];
 61         cnt[x] = cnt[z] + 1;
 62     }
 63     else {
 64         tto[x] = z;
 65         cnt[x] = 1;
 66     }
 67 }
 68 void Build(int x){
 69     Update(x);
 70     for(int i = head[x]; ~i; i = nt[i])
 71         Build(to[i]);
 72 }
 73 inline int solve(int p){
 74     int ret = 0;
 75     while(p){
 76         ret += cnt[p];
 77         p = tto[p];
 78     }
 79     return ret;
 80 }
 81 void dUpdate(int x){
 82     Update(x);
 83     for(int i = head2[x]; ~i; i = nt2[i]){
 84         dUpdate(to2[i]);
 85     }
 86 }
 87 void dfs2(int x){
 88     for(int i = head[x]; ~i; i = nt[i]){
 89         if(belong[x] == belong[to[i]]){
 90             add2(x, to[i]);
 91         }
 92         dfs2(to[i]);
 93     }
 94 }
 95 int main(){
 96     int t, x;
 97     scanf("%d", &t);
 98     while(t--){
 99         scanf("%d", &n);
100         b = sqrt(n);
101         tot = 0;top = 0; type = 0;tot2 = 0;
102         memset(head, -1, sizeof(int)*(n+1));
103         memset(head2, -1, sizeof(int)*(n+1));
104         for(int i = 2; i <= n; i++){
105             scanf("%d", &x);
106             add(x, i);
107         }
108         dfs(1);
109         while(top) belong[Stack[top--]] = type;
110         dfs2(1);
111         for(int i = 1; i <= n; i++){
112             scanf("%d", &x);
113             jump[i] = Find(i, x);
114         }
115         Build(1);
116         scanf("%d", &m);
117         int op, k;
118         while(m--){
119             scanf("%d", &op);
120             if(op == 1) {
121                 scanf("%d", &x);
122                 printf("%d\n", solve(x));
123             }
124             else {
125                 scanf("%d%d", &x, &k);
126                 jump[x] = Find(x, k);
127                 dUpdate(x);
128             }
129         }
130     }
131     return 0;
132 }
View Code

 

还有1种lct的写法,和弹飞绵羊的写法差不多,唯一有区别的就是找落地点在哪里,直接套lct的板子就好了,再用倍增找下一次去的位置就好了。

代码:

  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 tr[x].son[0]
 12 #define rch 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 int n, m, b;
 21 int head[N], to[N], nt[N];
 22 int tot, top, type, tot2;
 23 int anc[N][20];
 24 inline void add(int u, int v){
 25     to[tot] = v;
 26     nt[tot] = head[u];
 27     head[u] = tot++;
 28 }
 29 void dfs(int u){
 30     int now = top, v;
 31     for(int i = head[u]; ~i; i = nt[i]){
 32         v = to[i];
 33         anc[v][0] = u;
 34         for(int i = 1; i < 20; i++)
 35             anc[v][i] = anc[anc[v][i-1]][i-1];
 36         dfs(v);
 37     }
 38 }
 39 inline int Find(int x, int k){
 40     for(int i = 19; i >= 0; i--)
 41         if((k>>i)&1) x = anc[x][i];
 42     return x;
 43 }
 44 struct Node{
 45     int son[2], pre;
 46     int sz, is_root;
 47     inline void init() {
 48         son[1] = son[0] = pre = 0;
 49         sz = is_root =1;
 50     }
 51 }tr[N];
 52 void Push_Up(int x){
 53     if(!x) return ;
 54     tr[x].sz = tr[lch].sz + tr[rch].sz + 1;
 55 }
 56 void rotate(int x){
 57     if(tr[x].is_root) return ;
 58     int y = tr[x].pre, z = tr[y].pre;
 59     int k = x == tr[y].son[1];
 60     tr[y].son[k] = tr[x].son[k^1];
 61     tr[tr[y].son[k]].pre = y;
 62     tr[x].son[k^1] = y;
 63     tr[y].pre = x;
 64     tr[x].pre = z;
 65     if(tr[y].is_root) tr[x].is_root = 1, tr[y].is_root = 0;
 66     else tr[z].son[ tr[z].son[1] == y] = x;
 67     Push_Up(y);
 68 
 69 }
 70 void Splay(int x){
 71     while(!tr[x].is_root){
 72         int y = tr[x].pre, z = tr[y].pre;
 73         if(!tr[y].is_root){
 74             if((y == tr[z].son[1]) != ( x == tr[y].son[1])) rotate(y);
 75             else rotate(x);
 76         }
 77         rotate(x);
 78     }
 79     Push_Up(x);
 80 }
 81 void access(int x){
 82     int y = 0;
 83     do{
 84         Splay(x);
 85         tr[rch].is_root = 1;
 86         rch = y;
 87         tr[rch].is_root = 0;
 88         Push_Up(x);
 89         y = x;
 90         x = tr[x].pre;
 91     }while(x);
 92 }
 93 inline void link(int u, int v){
 94     if(v > n) v = 0;
 95     tr[u].pre = v;
 96 }
 97 inline void cut(int x){
 98     access(x);
 99     Splay(x);
100     tr[lch].is_root = 1;
101     tr[lch].pre = 0;
102     lch = 0;
103     Push_Up(x);
104 }
105 inline int Query(int x){
106     access(x);
107     Splay(x);
108     return tr[lch].sz + 1;
109 }
110 int main(){
111     int t, x;
112     scanf("%d", &t);
113     while(t--){
114         scanf("%d", &n);
115         tot = 0;
116         memset(head, -1, sizeof(int)*(n+1));
117         tr[1].init();
118         for(int i = 2; i <= n; i++){
119             tr[i].init();
120             scanf("%d", &x);
121             add(x, i);
122         }
123         dfs(1);
124         for(int i = 1; i <= n; i++){
125             scanf("%d", &x);
126             link(i, Find(i,x));
127         }
128         scanf("%d", &m);
129         int op, k;
130         while(m--){
131             scanf("%d", &op);
132             if(op == 1) {
133                 scanf("%d", &x);
134                 printf("%d\n", Query(x));
135             }
136             else {
137                 scanf("%d%d", &x, &k);
138                 cut(x);
139                 link(x, Find(x,k));
140             }
141         }
142     }
143     return 0;
144 }
View Code

虽然dls说分块和lct复杂度差不多, 但是这2份代码相比较lct快了100多, 实际上我觉得树上分块比较玄学。

posted @ 2018-08-14 08:28  Schenker  阅读(442)  评论(0编辑  收藏  举报