Codeforces Round #200 (Div. 1) D - Water Tree 很经典而且很有趣的树 上dfs问题

这道题疯狂wa了一大波,因为自己的线段树水平不够,更新 和 区间的理解还是大大的不够,所以一定要去多多学习。
题意:
给一颗树,有多次操作,有三种操作: 1. 把节点v 的所有 儿子节点(子树下的所有点)都充满水,2把节点v 的所有父亲节点的水都抽调。3.询问某个节点里面是否有水

.

一开始很年轻
感觉上 先跑出 dfs序,然后线段树维护一下节点flag值 就行了
好像感觉并不对,仔细想了想,如果我要把一个区间为: 2-4 这个节点 x清空,那么意味着x 有两个子节点1(3.3) 和2(4.4) 但是我不能把 1和2 清空啊。‘

那么我们在更新的时候修改一下姿势,和更新姿势没有关系,哪一种都是那样更新的
我们up 节点x的时候可以 吧区间弄为 L[x],L[x] ,这样就只会改变x 的祖先节点的flag值。

但是询问结果我们发现还是无法询问,因为区间不可能有两个啊,
那我们只能建两棵树了, 干脆区别对待
对于每一次的询问,我们都在两棵树上对同一个节点进行询问,看最后一次更新是1,还是2,由此便可得到是否有水

!!!!!!!仔细看看 线段树的更新 和询问 ,区间是很值得研究的 !!!!!!!

代码贴别人的,自己写的太丑了,就不拿出来了,蛤蛤

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define INF 0x7fffffff //INT_MAX
#define inf 0x3f3f3f3f //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
bool cmpbig(int a,int b){return a>b;}
bool cmpsmall(int a,int b){return a<b;}
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int N=500005;
using namespace std;
vector<int> E[N];
int i, j, k, l, x, type, y, dfn[N], dfn2[N], tim, n, m;

struct seg_tree {
  int s[N * 4], sign[N * 4];
  void cover(int p, int l, int r, int x, int y, int k) {
    if (x <= l && y >= r) {
      s[p] = sign[p] = k;
// printf("i=%d p=%d s=%d\n",i,p,s[p]);
      return;
    }
    int mid = l + r >> 1;
    if (x <= mid) cover(p << 1, l, mid, x, y, k);
    if (y > mid) cover((p << 1) + 1, mid + 1, r, x, y, k);
    s[p] = max(s[p << 1], s[(p << 1) + 1]);
// printf("i=%d p=%d s=%d\n",i,p,s[p]);
  }
  int calc(int p, int l, int r, int x, int y) {
    if (x <= l && y >= r) return s[p];
    int mid = l + r >> 1, res = 0;
    if (x <= mid) res = max(res, calc(p << 1, l, mid, x, y));
    if (y > mid) res = max(res, calc((p << 1) + 1, mid + 1, r, x, y));
    return max(sign[p], res);
  }
} T1, T2;
void dfs(int x, int ff) {
  dfn[x] = ++tim;
  for (int i = E[x].size() - 1; i >= 0; --i)
    if (E[x][i] != ff) dfs(E[x][i], x);
  dfn2[x] = tim;
}
int main() {
  scanf("%d", &n);
  for (i = 1; i < n; ++i) {
    scanf("%d%d", &x, &y);
    E[x].push_back(y);
    E[y].push_back(x);
  }
  dfs(1, 0);
  scanf("%d", &m);
  for (i = 1; i <= m; ++i) {
    scanf("%d%d", &type, &x);
    if (type == 1) {
      T1.cover(1, 1, n, dfn[x], dfn2[x], i);
    }
    if (type == 2) {
      T2.cover(1, 1, n, dfn[x], dfn[x], i);
    }
    if (type == 3) {
      int v1 = T1.calc(1, 1, n, dfn[x], dfn[x]);
      int v2 = T2.calc(1, 1, n, dfn[x], dfn2[x]);
// printf("v= %d %d\n",v1,v2);
      if (v2 >= v1)
        puts("0");
      else
        puts("1");
    }
  }
}

你可能感兴趣的:(Codeforces Round #200 (Div. 1) D - Water Tree 很经典而且很有趣的树 上dfs问题)