posted on 2019-10-07 20:21:57

Apple Tree 2

题目描述

有一颗 \(n\) 个节点的苹果树,最初每个节点上都有 \(1\) 个苹果,并且每个节点在操作的过程中只会处在有 \(1\) 个苹果和没有苹果两种状态之一。

\(m\) 个操作,操作分为三种:

  • 发动丰收魔法:令节点 \(u\) 为根的子树中所有没有苹果的节点全部长出 个苹果。

  • 摘下苹果吃:令节点 \(u\) 为根的子树中所有有苹果的节点的苹果全部消失。

  • 统计苹果个数:统计节点 \(u\) 为根的子树中苹果的个数。

输入格式

从标准输入读入数据。

第一行输入三个正整数 \(n(n \leq 10^5), m(m \leq 10^5)\)\(root(root \leq n)\),其中 \(root\) 代表根节点编号。

接下来 \(n - 1\) 行,每行输入两个整数 \(x\)\(y(1 \leq x, y \leq n)\),代表 \(x\)\(y\) 之间连有边。

接下来 \(m\) 行,每行输入两个整数 \(opt\)(取值 \(0\)\(1\)\(2\))和 \(u(1 \leq u \leq n)\),其中\(opt = 0\) 表示这是一次丰收魔法、\(opt = 1\) 表示这是一次摘苹果、\(opt = 2\) 表示这是一次统计。

输出格式

输出到标准输出。

对于每个统计操作,输出一行一个整数代表所求答案。

样例输入

5 9 1
2 1
3 2
4 1
5 2
1 1
0 2
2 3
2 2
0 4
2 1
0 1
1 2
2 1

样例输出

1
3
4
2

很好的一个线段树与\(DFS\)序结合的题目

因为一棵树的子树的\(DFS\)序是连续的,因此直接按\(DFS\)序建线段树,子树修改与查询都变为了区间修改与查询

代码如下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N = 1e5 + 3;
int n, m, rt;
struct edge {
    int to, next;
} e[N << 1];
int head[N], cnt, a[N], vis[N], size[N], pos[N], sum[N << 2], tag[N << 2];
void add(int u, int v)
{
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
void dfs(int k)
{
    size[k] = 1;
    vis[k] = 1;
    for(int i = head[k]; i; i = e[i].next) {
        int v = e[i].to;
        if(!vis[v]) {
            a[++cnt] = v;
            pos[v] = cnt;
            dfs(v);
            size[k] += size[v];
        }
    }
}

//int dfn[N][2], tm;
//void dfs(int u) {
//    vis[u] = 1;
//    dfn[u][0] = ++tm;
//    for(int i = head[u]; i; i = e[i].next) {
//      int v = e[i].to;
//      if(!vis[v])
//            dfs(v);
//    }
//    dfn[u][1] = tm;
//}
void pushup(int u)
{
    sum[u] = sum[u << 1] + sum[u << 1 | 1];
}
void build(int u, int ul, int ur)
{
    tag[u] = -1;
    if(ul == ur) {
        sum[u] = 1;
        return;
    }
    int mid = ul + ur >> 1;
    build(u << 1, ul, mid);
    build(u << 1 | 1, mid + 1, ur);
    pushup(u);
}
void update(int u, int ul, int ur, int x)
{
    if(x == 0)
        sum[u] = ur - ul + 1;
    else
        sum[u] = 0;
    tag[u] = x;
}
void pushdown(int u, int ul, int ur)
{
    if(tag[u] != -1) {
        int mid = ul + ur >> 1;
        update(u << 1, ul, mid, tag[u]);
        update(u << 1 | 1, mid + 1, ur, tag[u]);
        tag[u] = -1;
    }
}
void modify(int u, int ul, int ur, int ml, int mr, int mx)
{
    if(ul >= ml && ur <= mr) {
        update(u, ul, ur, mx);
        return;
    }
    pushdown(u, ul, ur);
    int mid = ul + ur >> 1;
    if(mid >= ml)
        modify(u << 1, ul, mid, ml, mr, mx);
    if(mid + 1 <= mr)
        modify(u << 1 | 1, mid + 1, ur, ml, mr, mx);
    pushup(u);
}
int query(int u, int ul, int ur, int ml, int mr)
{
    if(ml <= ul && mr >= ur) {
        return sum[u];
    }
    pushdown(u, ul, ur);
    int mid = ul + ur >> 1;
    int s = 0;
    if(mid >= ml) {
        s += query(u << 1, ul, mid, ml, mr);
    }
    if(mid + 1 <= mr) {
        s += query(u << 1 | 1, mid + 1, ur, ml, mr);
    }
    return s;
}
int main()
{
    cin >> n >> m >> rt;
    for(int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        add(x, y);
        add(y, x);
    }
    cnt = 1;
    a[1] = rt;
    pos[rt] = 1;
    dfs(rt);
//  for(int i = 1; i <= n; i++) {
//      cout << size[i] << endl;
//  }
    build(1, 1, n);
    while(m--) {
        int opt, u;
        cin >> opt >> u;
        if(opt == 0 || opt == 1) {
            modify(1, 1, n, pos[u], pos[u] + size[u] - 1, opt);
//          cout << query(1, 1, n, pos[u], pos[u] + size[u] - 1) << endl;
        } else {
            cout << query(1, 1, n, pos[u], pos[u] + size[u] - 1) << endl;
        }
    }
    return 0;
}
  1. 数组一定要开四倍大小

  2. tag标记的是啥一定要想清楚

void update(int u, int ul, int ur, int x)
{
    if(x == 0)
        sum[u] = ur - ul + 1;
    else
        sum[u] = 0;
    tag[u] = x;
}
void pushdown(int u, int ul, int ur)
{
    if(tag[u] != -1) {
        int mid = ul + ur >> 1;
        update(u << 1, ul, mid, tag[u]);
        update(u << 1 | 1, mid + 1, ur, tag[u]);
        tag[u] = -1;
    }
}

特别是这两处tag的更新

12-31 11:36