题意:给你一颗n个节点的树,1为根,初始时所有节点都为0,有三种操作:
1 x :将x及其子树的所有节点都变为1
2 x :将x及其祖先都变为0
3 x :查询x的值
思路:可以先求出dfs序,对于操作1,我们可以用线段树区间更新in[x]至out[x];对于操作2,需要更新它及其祖先,
不太好操作,我们可以只将x变为0,这样对于操作3,我们可以查找其子树最小值,如果是0就代表它也会变为0,否
则就是1。这样一来操作1可能会把操作2的0给覆盖掉,所以在进行操作1时要把其父节点变为0。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+5;
int tree[maxn*4], lazy[maxn*4], in[maxn*4], out[maxn*4], fa[maxn*4], tot;
vector<int> g[maxn];
void dfs(int u, int pre)
{
in[u] = ++tot;
fa[u] = pre;
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(v != pre)
dfs(v, u);
}
out[u] = tot;
}
void push_up(int root)
{
tree[root] = min(tree[root*2], tree[root*2+1]);
}
void push_down(int root)
{
if(lazy[root] != -1)
{
tree[root*2] = tree[root*2+1] = lazy[root];
lazy[root*2] = lazy[root*2+1] = lazy[root];
lazy[root] = -1;
}
}
void update(int root, int l, int r, int i, int j, int op)
{
if(i <= l && j >= r)
{
tree[root] = lazy[root] = op;
return ;
}
push_down(root);
int mid = (l+r)/2;
if(i <= mid)
update(root*2, l, mid, i, j, op);
if(j > mid)
update(root*2+1, mid+1, r, i, j, op);
push_up(root);
}
int query(int root, int l, int r, int i, int j)
{
if(i <= l && j >= r)
return tree[root];
push_down(root);
int mid = (l+r)/2;
if(j <= mid) return query(root*2, l, mid, i, j);
else if(i > mid) return query(root*2+1, mid+1, r, i, j);
else return min(query(root*2, l, mid, i, j), query(root*2+1, mid+1, r, i, j));
}
int main(void)
{
int n;
while(cin >> n)
{
tot = 0;
memset(tree, 0, sizeof(tree));
memset(lazy, -1, sizeof(lazy));
for(int i = 0; i <= n; i++)
g[i].clear();
for(int i = 0; i < n-1; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
int q;
scanf("%d", &q);
while(q--)
{
int cmd, x;
scanf("%d%d", &cmd, &x);
if(cmd == 1)
{
int tmp = query(1, 1, tot, in[x], out[x]);
update(1, 1, tot, in[x], out[x], 1);
if(!tmp && fa[x])
update(1, 1, tot, in[fa[x]], in[fa[x]], 0);
}
else if(cmd == 2)
update(1, 1, tot, in[x], in[x], 0);
else
printf("%d\n", query(1, 1, tot, in[x], out[x]));
}
}
return 0;
}