uoj128/bzoj4196/NOI2015.软件包管理器(树链剖分)
2015-12-04 09:14
274 查看
有 n 个软件,他们之间有
n - 1 种依赖关系:假如 A 依赖 B,那么安装
A 之前必须先安装 B, 卸载 B 之前必须先卸载 A。现在有
m 条操作,每个会卸载或者安装一个软件,你的任务是对于每次操作,求出这个操作实际改变了几个软件的状态,即从未安装变为安装,或从安装变为未安装。
首先显然的是,软件之间的依赖关系构成了一颗树,每个节点的安装操作只和它的祖先有关,假如用
01 表示,就是求从根到此节点这条路径上 0 的个数;卸载操作只与它的子树有关,即求子树中有多少个
1。所以用树链剖分可以实现。
n - 1 种依赖关系:假如 A 依赖 B,那么安装
A 之前必须先安装 B, 卸载 B 之前必须先卸载 A。现在有
m 条操作,每个会卸载或者安装一个软件,你的任务是对于每次操作,求出这个操作实际改变了几个软件的状态,即从未安装变为安装,或从安装变为未安装。
首先显然的是,软件之间的依赖关系构成了一颗树,每个节点的安装操作只和它的祖先有关,假如用
01 表示,就是求从根到此节点这条路径上 0 的个数;卸载操作只与它的子树有关,即求子树中有多少个
1。所以用树链剖分可以实现。
#include <cstdio> #include <algorithm> using namespace std; const int MAX_N = 100005; struct tree{ int v, next; }E[MAX_N << 1]; int head[MAX_N], tag = 0; inline void add(int u, int v){ E[++ tag].v = v; E[tag].next = head[u]; head[u] = tag; } int deep[MAX_N], siz[MAX_N], son[MAX_N], fa[MAX_N], top[MAX_N], id[MAX_N], subtree[MAX_N], num; void dfs1(int x, int last, int d) { deep[x] = d; siz[x] = 1; son[x] = 0; fa[x] = last; for (int i = head[x]; i; i = E[i].next){ if (E[i].v == last) continue; dfs1(E[i].v, x, d + 1); siz[x] += siz[E[i].v]; if (siz[son[x]] < siz[E[i].v]) son[x] = E[i].v; } } void dfs2(int x, int tp) { top[x] = tp; id[x] = ++ num; if (son[x]) dfs2(son[x], tp); for (int i = head[x]; i; i = E[i].next){ if (E[i].v == fa[x] || E[i].v == son[x]) continue; dfs2(E[i].v, E[i].v); } subtree[x] = num; } struct node{ int l, r, sum, tot, flag; }a[MAX_N << 2]; int n, q; inline void tree_pd(int i) { if (a[i].flag != -1){ a[i << 1].sum = a[i << 1].tot * a[i].flag; a[i << 1 | 1].sum = a[i << 1 | 1].tot * a[i].flag; a[i << 1].flag = a[i << 1 | 1].flag = a[i].flag; a[i].flag = -1; } } void make_tree(int i, int l, int r) { a[i].l = l; a[i].r = r;a[i].tot = r - l + 1; a[i].sum = 0; a[i].flag = -1; if (a[i].l == a[i].r) return; int mid = (a[i].l + a[i].r) >> 1; make_tree(i << 1, l, mid); make_tree(i << 1 | 1, mid + 1, r); } void tree_modify(int i, int l, int r, int c) { if (a[i].l == l && a[i].r == r){ a[i].sum = a[i].tot * c; a[i].flag = c; return; } tree_pd(i); int mid = (a[i].l + a[i].r) >> 1; if (r <= mid) tree_modify(i << 1, l, r, c); else if (l > mid) tree_modify(i << 1 | 1, l, r, c); else tree_modify(i << 1, l, mid, c), tree_modify(i << 1 | 1, mid + 1, r, c); a[i].sum = a[i << 1].sum + a[i << 1 | 1].sum; } int tree_query(int i, int l, int r) { if (a[i].l == l && a[i].r == r) return a[i].sum; tree_pd(i); int mid = (a[i].l + a[i].r) >> 1; if (r <= mid) return tree_query(i << 1, l, r); else if (l > mid) return tree_query(i << 1 | 1, l, r); else return tree_query(i << 1, l, mid) + tree_query(i << 1 | 1, mid + 1, r); } void tree_change(int x, int y) { int ans = 0, sum = deep[y] - deep[x] + 1; while (top[x] != top[y]){ if (deep[top[x]] < deep[top[y]]) swap(x, y); ans += tree_query(1, id[top[x]], id[x]); tree_modify(1, id[top[x]], id[x], 1); x = fa[top[x]]; } if (deep[x] > deep[y]) swap(x, y); ans += tree_query(1, id[x], id[y]); tree_modify(1, id[x], id[y], 1); printf("%d\n", sum - ans); } void init() { scanf("%d", &n); for (int i = 2; i <= n; i ++){ int x; scanf("%d", &x); x ++; add(x, i); add(i, x); } } void doit() { num = 0; dfs1(1, 0, 1); dfs2(1, 1); make_tree(1, 1, num); scanf("%d", &q); char s[10]; while (q --){ int x; scanf("%s%d", s + 1, &x); x ++; if (s[1] == 'i') tree_change(1, x); else { printf("%d\n", tree_query(1, id[x], subtree[x])); //printf("%d %d %d %d\n", tree_query(1, 2, 2), tree_query(1, 3, 3), tree_query(1, 4, 4), tree_query(1, 5, 5)); tree_modify(1, id[x], subtree[x], 0); } } } int main() { init(); doit(); return 0; }
相关文章推荐
- DB2新建实例参数
- yii2 表单错误提示
- 轻松学习JavaScript四:JS点击灯泡来点亮或熄灭这盏灯的网页特效映射出JS在HTML中作用
- 第十四周项目2-二叉树排序树中查找的路径
- 第九周项目四:广义表算法库及应用(1)
- awk学习笔记
- libsvm在matlab中的使用方法
- OpenCV图片拼接
- 6-《电子入门趣谈》第一章_一切从单片机开始-1.3.3按键
- jquery.js 库中的 选择器
- Swift is Now Open Source
- python3学习爬虫 正则以及url
- USING THE ANDROID TOOLCHAIN AS A STANDALONE COMPILER
- plSQL复制数据的方法
- (并查集) NYOJ 1022 合纵连横
- Swift 踩坑
- 打包的安装包不能正常显示百度地图解决办法
- Set接口
- SP2-0618和_SP2-0611错误处理(转)
- onCreateOptionsMenu中menu.add参数解析