dfs+线段树 zhrt的数据结构课

zhrt的数据结构课

这个题目我觉得是一个有一点点思维的dfs+线段树

虽然说看起来可以用树链剖分写,但是这个题目时间卡了树剖

因为之前用树剖一直在写这个,所以一直想的是区间更新,想dfs+线段树,有点点没想明白

后来才知道可以把这个区间更新转化成单点更新,就是查一个结点的子树,如果子树有可以到根节点的,那么这个结点肯定也可以到根节点。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <stack>
#include <map>
#include <string>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 4e5 + 10;
int sum[maxn * 4];

void push_up(int id)
{
	sum[id] = sum[id << 1 | 1] + sum[id << 1];
}

void build(int id,int l,int r)
{
	if(l==r)
	{
		sum[id] = 0;
		return;
	}
	int mid = (l + r) >> 1;
	build(id << 1, l, mid);
	build(id << 1 | 1, mid + 1, r);
	push_up(id);
}

void update(int id,int l,int r,int pos,int val)
{
	if(l==r)
	{
		sum[id] += val;
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid) update(id << 1, l, mid, pos, val);
	else update(id << 1 | 1, mid + 1, r, pos, val);
	push_up(id);
}

int query(int id,int l,int r,int x,int y)
{
	// printf("id=%d l=%d r=%d x=%d y=%d\n", id, l, r, x, y);
	if (x <= l && y >= r) return sum[id];
	int mid = (l + r) >> 1;
	int ans = 0;
	if (x <= mid) ans += query(id << 1, l, mid, x, y);
	if (y > mid) ans += query(id << 1 | 1, mid + 1, r, x, y);
	return ans;
}
int el[maxn], er[maxn], tot = 0, head[maxn], cnt;
struct node
{
	int v, nxt;
	node(int v=0,int nxt=0):v(v),nxt(nxt){}
}ex[maxn];

void init()
{
	memset(head, -1, sizeof(head));
	tot = 0, cnt = 0;
}

void add(int u,int v)
{
	ex[cnt] = node(v, head[u]);
	head[u] = cnt++;
	ex[cnt] = node(u, head[v]);
	head[v] = cnt++;
	// printf("u=%d v=%d\n", u, v);
}

void dfs(int u,int pre)
{
	el[u] = ++tot;
	for(int i=head[u];i!=-1;i=ex[i].nxt)
	{
		int v = ex[i].v;
		if (v == pre) continue;
		dfs(v, u);
	}
	er[u] = tot;
	// printf("el[%d]=%d er[%d]=%d\n", u, el[u], u, er[u]);
}

int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		init();
		int n, m;
		scanf("%d%d", &n, &m);
		build(1, 1, n);
		for(int i=1;i<n;i++)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			add(u, v);
		}
		dfs(1, -1);
		while(m--)
		{
			int opt, x;
			scanf("%d%d", &opt, &x);
			if (opt == 0) update(1, 1, n, el[x], 1);
			if (opt == 1) update(1, 1, n, el[x], -1);
			if (opt == 2)
			{
				int ans = query(1, 1, n, el[x], er[x]);
				if (ans) printf("Yes\n");
				else printf("No\n");
			}
		}
	}
}

  

原文地址:https://www.cnblogs.com/EchoZQN/p/11334372.html

时间: 2024-10-25 07:25:30

dfs+线段树 zhrt的数据结构课的相关文章

2014 Super Training #9 F A Simple Tree Problem --DFS+线段树

原题: ZOJ 3686 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686 这题本来是一个比较水的线段树,结果一个mark坑了我好几个小时..哎.太弱. 先DFS这棵树,树形结构转换为线性结构,每个节点有一个第一次遍历的时间和最后一次遍历的时间,之间的时间戳都为子树的时间戳,用线段树更新这段区间即可实现更新子树的效果,用到懒操作节省时间. 坑我的地方: update时,不能写成:tree[rt].mark = 1,

HDU 5877 dfs+ 线段树(或+树状树组)

1.HDU 5877  Weak Pair 2.总结:有多种做法,这里写了dfs+线段树(或+树状树组),还可用主席树或平衡树,但还不会这两个 3.思路:利用dfs遍历子节点,同时对于每个子节点au,查询它有多少个祖先av满足av<=k/au. (1)dfs+线段树 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm>

POJ 3321 Apple Tree (dfs+线段树)

题目大意: 修改树上的节点,然后求子树的和. 思路分析: dfs 重新编号,烂大街了... #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define maxn 100005 #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e using namespace std

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

【Codeforces-707D】Persistent Bookcase DFS + 线段树

D. Persistent Bookcase Recently in school Alina has learned what are the persistent data structures: they are data structures that always preserves the previous version of itself and access to it when it is modified. After reaching home Alina decided

hdu-2586 How far away ?(lca+bfs+dfs+线段树)

题目链接: How far away ? Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this

线段树讲解(数据结构、C++)

声明    : 仅一张图片转载于http://www.cnblogs.com/shuaiwhu/archive/2012/04/22/2464583.html,自己画太麻烦了...那个博客的讲解也很好,只是他用了指针的方式来定义线段树,而我用了结构体,并且他讲了线段树的更高级的操作,若对线段树的初级操作不理解,请继续阅读 线段树作为一种十分常用的数据结构,在NOIP.NOI中广泛的出现,所以在这里对线段树进行简单的讲解. 线段树支持对一个数列的求和.单点修改.求最值(最大.最小).区间修改(需要

HDU5692 Snacks DFS+线段树

分析:一棵以1为根的有根树,然后每个点维护从根到当前节点的路径和,当修改一个点时 只会影响的子树的和,最优值也是子树最大的值 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; const int N=1e5+5; const LL INF=1ll*1e11; struc

HDU5692 dfs + 线段树维护区间最大值

先附上题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692 Problem Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化.小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次.另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机. 为小度熊规划一个路线,使得路线上的价值总和最