您的位置:首页 > 其它

uoj128/bzoj4196/NOI2015.软件包管理器(树链剖分)

2015-12-04 09:14 274 查看
n 个软件,他们之间有
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: