zoukankan      html  css  js  c++  java
  • Apple Tree 2

    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的更新

  • 相关阅读:
    解决吞吐性能问题时的思路
    mysql left join转inner join
    TypeScript 在开发应用中的实践总结
    antd+react项目迁移vite的解决方案
    客官,.NETCore无代码侵入的模型验证了解下
    v-html可能导致的问题
    IDA反汇编EXE添加一个启动时的消息框
    OD反汇编EXE添加一个启动时的消息框
    Vue中的三种Watcher
    React中diff算法的理解
  • 原文地址:https://www.cnblogs.com/xuanfly/p/11808572.html
Copyright © 2011-2022 走看看