bzoj4196: [Noi2015]软件包管理器(树链剖分)

bzoj4196

太久没写树剖都忘了,赶紧来写写。

题目描述:有n个软件,每个软件都有一个且仅有一个依赖关系,只有安装了依赖的软件才能安装这个软件。0节点没有依赖关系。

                  给定q个询问,每个询问为安装或卸载某个软件,问每次询问会改变多少个软件的安装状态。

输入格式:第一行一个整数表示n。

                 第二行第i个表示第i个软件的依赖软件。

                 第三行一个整数q,表示询问的个数。

                 接下来q行每行一个询问,install x 表示安装编号为 x 的软件。uninstall x 表示卸载编号为 x 的软件。

输出格式:每个询问,输出一个整数,表示会改变的软件状态。

输入样例:

7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0

输出样例:

3
1
3
2
3

解析:一道树剖的模板题,用0表示没有安装,用1表示安装了。每次安装操作就输出dep[x] - x到根节点的1的个数,再将根节点到 x 变为1。

          卸载时就询问 x 的子树中1的个数,再全部改为0即可。因为 x 的子树中的dfs序是连续的,所以直接用子树的大小就可以知道在线段树上的标号。

代码如下:

  1 #include<cstdio>
  2 #include<vector>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define lc o << 1
  6 #define rc o << 1 | 1
  7 using namespace std;
  8 
  9 const int maxn = 1e5 + 5;
 10 int n, bj[maxn * 4], sum[maxn * 4], q;
 11 int dfn[maxn], cnt, dep[maxn], fa[maxn], seq[maxn], size[maxn], heavy[maxn], top[maxn];
 12 char s[15];
 13 vector <int> ve[maxn];
 14 
 15 int read(void) {
 16     char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0';
 17     while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x;
 18 }
 19 
 20 void dfs1(int u, int pre) {
 21     dep[u] = dep[pre] + 1;
 22     fa[u] = pre; size[u] = 1;
 23       for (int i = 0; i < ve[u].size(); ++ i) {
 24           int v = ve[u][i];
 25             if (v == pre) continue;
 26           dfs1(v, u);
 27           size[u] += size[v];
 28             if (size[v] > size[heavy[u]]) heavy[u] = v;
 29       } 
 30 }
 31 
 32 void dfs2(int u, int cur) {
 33     top[u] = cur; dfn[u] = ++ cnt; 
 34     seq[cnt] = u; //seq对这题好像没什么用,但还是打了 QAQ 
 35       if (!heavy[u]) return;
 36     dfs2(heavy[u], cur);
 37       for (int i = 0; i < ve[u].size(); ++ i) {
 38           int v = ve[u][i];
 39             if (v == fa[u] || v == heavy[u]) continue;
 40           dfs2(v, v);
 41       }
 42 }
 43 
 44 void pushdown(int o, int l, int r) {
 45     int mid = l + r >> 1;
 46     sum[lc] = bj[o] * (mid - l + 1);
 47     sum[rc] = bj[o] * (r - mid);
 48     bj[lc] = bj[rc] = bj[o]; bj[o] = -1;
 49 }
 50 
 51 void modify(int o, int l, int r, int ql, int qr, int c) {
 52     if (ql <= l && qr >= r) {
 53       sum[o] = c * (r - l + 1); bj[o] = c;
 54       return;
 55     }
 56     int mid = l + r >> 1;
 57     if (bj[o] != -1) pushdown(o, l, r);
 58     if (ql <= mid) modify(lc, l, mid, ql, qr, c);
 59     if (qr > mid) modify(rc, mid + 1, r, ql, qr, c);
 60     sum[o] = sum[lc] + sum[rc];
 61 }
 62 
 63 int query(int o, int l, int r, int ql, int qr) {
 64     if (ql <= l && qr >= r) return sum[o];
 65     int mid = l + r >> 1, ans = 0;
 66     if (bj[o] != -1) pushdown(o, l, r);
 67     if (ql <= mid) ans += query(lc, l, mid, ql, qr);
 68     if (qr > mid) ans += query(rc, mid + 1, r, ql, qr);
 69     return ans;
 70 }
 71 
 72 void chain_modify(int x, int y, int c) {
 73     int fax = top[x], fay = top[y];
 74       while (fax != fay) {
 75           if (dep[fax] < dep[fay]) {
 76               swap(fax, fay);
 77               swap(x, y);
 78           }
 79         modify(1, 1, n, dfn[fax], dfn[x], c);
 80         x = fa[fax];
 81         fax = top[x];
 82       }
 83       if (dep[x] > dep[y]) swap(x, y);
 84     modify(1, 1, n, dfn[x], dfn[y], c);
 85 }
 86 
 87 int chain_query(int x, int y) {
 88     int fax = top[x], fay = top[y], ans = 0;
 89       while (fax != fay) {
 90           if (dep[fax] < dep[fay]) {
 91               swap(fax, fay);
 92               swap(x, y);
 93           }
 94         ans += query(1, 1, n, dfn[fax], dfn[x]);
 95         x = fa[fax];
 96         fax = top[x];
 97       }
 98       if (dep[x] > dep[y]) swap(x, y);
 99     ans += query(1, 1, n, dfn[x], dfn[y]);
100     return ans;
101 }
102 
103 int main() {
104     n = read(); 
105       for (int i = 2; i <= n; ++ i) {
106           int x = read() + 1;
107           ve[x].push_back(i);
108           ve[i].push_back(x);
109       }
110     q = read();
111     dfs1(1, 0);
112     dfs2(1, 1);
113     memset(bj, -1, sizeof(bj));
114       while (q --) {
115           scanf("%s", s + 1);
116           int x = read() + 1;
117             if (s[1] == 'i') {
118                   int ans = dep[x] - chain_query(1, x);
119                   if (ans < 0) {
120                           ans = ans;
121                           ans = chain_query(1, x);
122                   }
123                   printf("%d
", dep[x] - chain_query(1, x));
124                   chain_modify(1, x, 1);
125             }
126           else {
127               printf("%d
", query(1, 1, n, dfn[x], dfn[x] + size[x] - 1)); //直接用size算出子树中节点的dfs序最大值 
128               modify(1, 1, n, dfn[x], dfn[x] + size[x] - 1, 0);
129           }
130       }
131     return 0;
132 }
原文地址:https://www.cnblogs.com/Gaxc/p/9927063.html