bzoj 4196:[NOI2015] 软件包管理器 (树链剖分)

第一次做树剖

找同学要了模板 + 各种借鉴

先用dfs在划分轻重链并编号, install的时候就从查询的节点到根寻找标记的点有多少个,再用深度减去标记的点的个数,并把路径上所有点都标记

uninstall就是搜索查询的点的子树的标记个数,并取消所有的标记。

代码如下

  1 /**************************************************************
  2     Problem: 4196
  3     Language: C++
  4     Result: Accepted
  5     Time:8312 ms
  6     Memory:7416 kb
  7 ****************************************************************/
  8  
  9 #include <cstdio>
 10 #include <vector>
 11 #include <cstring>
 12 using namespace std;
 13 #define g(l, r) (l + r | l != r)
 14 #define o g(l, r)
 15 #define ls g(l, mid)
 16 #define rs g(mid + 1, r)
 17 const int N = 100100; 
 18  
 19 int n, dep[N], fa[N], hs[N], size[N], top[N], pos[N], mark[N<<1], sum[N<<1], tot, L, R, m;
 20 vector < int > edge[N];
 21  
 22 inline void dfs1(int u, int d, int f){
 23     dep[u] = d; fa[u] = f;  hs[u] = -1;  size[u] = 1;
 24     int tmp = 0;
 25     for (int i = 0; i < edge[u].size(); i++){
 26         int &v = edge[u][i];
 27         dfs1(v, d + 1, u);
 28         if (size[v] > tmp)
 29             hs[u] = v, tmp = size[v];
 30         size[u] += size[v];
 31     }
 32 }
 33  
 34 inline void dfs2(int u, int T){
 35     top[u] = T; pos[u] = ++tot;
 36     if (hs[u] == -1)    return ;
 37     dfs2(hs[u], T);
 38     for (int i = 0; i < edge[u].size(); i++){
 39         int &v = edge[u][i];
 40         if (hs[u] == v) continue;
 41         dfs2(v, v);
 42     }
 43 }
 44  
 45 inline void push(int l, int r) {
 46     if (mark[o] == -1) return;
 47     int mid = l + r >> 1;
 48     if (l < r) {
 49         mark[ls] = mark[o];
 50         sum[ls] = mark[o] * (mid - l  + 1);
 51         mark[rs] = mark[o];
 52         sum[rs] = mark[o] * (r - (mid + 1) + 1);
 53     }
 54     mark[o] = -1;
 55 }
 56  
 57 void modify(int l, int r){
 58     if (L <= l && r <= R){
 59         sum[o] = m * (r - l + 1);
 60         mark[o] = m;
 61         return ;
 62     }
 63     push(l, r);
 64     int mid = l + r >> 1;
 65     if (L <= mid)    modify(l, mid);
 66     if (R >= mid + 1)    modify(mid + 1, r);
 67     sum[o] = sum[ls] + sum[rs];
 68 }
 69  
 70 int getSum(int l, int r){
 71     if (L <= l && r <= R){
 72         return sum[o];
 73     }
 74     push(l, r);
 75     int mid = l + r >> 1, ans = 0;
 76     if (L <= mid)    ans += getSum(l, mid);
 77     if (R >= mid + 1)    ans += getSum(mid + 1, r);
 78     return ans;
 79 }
 80  
 81 inline void install(int u){
 82     int f = top[u], ans = dep[u];
 83     m = 1;
 84     while(f){
 85         L = pos[f], R = pos[u];
 86         ans -= getSum(1, tot);
 87         modify(1, tot);
 88         u = fa[f]; f = top[u];
 89     }
 90     L = pos[f], R = pos[u];
 91     ans -= getSum(1, tot);
 92     modify(1, tot);
 93     printf("%d\n", ans);
 94 }
 95  
 96 inline void uninstall(int u){
 97     L = pos[u], R = pos[u] + size[u] - 1, m = 0; 
 98     int ans = getSum(1, tot);
 99     modify(1, tot);
100     printf("%d\n", ans);
101 }
102  
103 int main(){
104     scanf("%d", &n);
105     for (int i = 1; i < n; i++){
106         int x; scanf("%d", &x);
107         edge[x].push_back(i);
108     }
109     dfs1(0, 1, -1);  dfs2(0, 0);
110     int q;
111     scanf("%d", &q);
112     memset(mark, 0xff, sizeof(mark));
113     while(q--){
114         char str[15]; int x;
115         scanf("%s%d", str, &x);
116         if (*str == 'i')    install(x);
117         else uninstall(x);
118     }
119     return 0;
120 } 

 

posted @ 2017-06-18 12:41  cminus  阅读(222)  评论(0编辑  收藏  举报