dfs序题集

dfs序可以维护一个子树内的信息

需要记录dfs进的时间以及所有子树都遍历完的时间

void dfs(int u, int fa)
{
	L[u] = ++id;
	for(int i = head[u]; ~i; i = e[i].next)
	{
		int v = e[i].to;
		if(v == fa) continue;
		dfs(v, u);
	}
	R[u] = id;
}

那么对于点i,L[i]到R[i]就是i的子树(包括i)

那么子树内维护信息就可以用树状数组,线段树之内的乱搞了。

 

poj 3321

用树状数组维护就好。

注意修改的时候一定是修改序列

#include<cstdio>
#include<cstring>
#include<cctype>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
 
const int MAXN = 1e5 + 10;
struct Edge{ int to, next; };
Edge e[MAXN << 1];
int head[MAXN], num, n, m;
int L[MAXN], R[MAXN], s[MAXN], id;

struct Binary_Index_Tree
{
	int f[MAXN];
	
	Binary_Index_Tree() { memset(f, 0, sizeof(f)); }
	
	int lowbit(int x) { return x & (-x); }
	
	void add(int x, int p)
	{
		while(x <= n)
		{
			f[x] += p; 
			x += lowbit(x);
		}
	}
	
	int sum(int x)
	{
		int res = 0;
		while(x)
		{
			res += f[x];
			x -= lowbit(x);
		}
		return res;
	}
	
	int query(int l, int r) { return sum(r) - sum(l - 1); }
}S;
 
void read(int& x)
{
	int f = 1; x = 0; char ch = getchar();
	while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
	while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
	x *= f;
}
 
void AddEdge(int to, int from)
{
	e[num] = Edge{to, head[from]};
	head[from] = num++;
}
 
void dfs(int u, int fa)
{
	L[u] = ++id;
	for(int i = head[u]; ~i; i = e[i].next)
	{
		int v = e[i].to;
		if(v == fa) continue;
		dfs(v, u);
	}
	R[u] = id;
}
 
int main()
{
	memset(head, -1, sizeof(head)); num = 0;
	read(n);
	REP(i, 1, n)
	{
		int u, v; read(u), read(v);
		AddEdge(u, v); AddEdge(v, u); 
	}
	_for(i, 1, n) 
	{
		s[i] = 1;
		S.add(i, 1);
	}
	
	dfs(1, -1);
	read(m);
	
	while(m--)
	{
		char op[5]; int x;
		scanf("%s", op); read(x);
		if(op[0] == 'Q') printf("%d\n", S.query(L[x], R[x]));
		else
		{
			int id = L[x];
			if(s[id]) S.add(id, -1);
			else S.add(id, 1);
			s[id] = !s[id];
		}
	}

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值