dfs序及其应用

dfs序是用来处理子树一类问题的,可以把子树问题转化为区间问题,以便借助线段树或树状数组处理。根据dfs的顺序来给节点编号,在进入这个节点时更新in数组,出去的时候更新out数组,这样以i为根的子树的操作就可以变成区间[in[i]…out[i]]的操作了。

int in[100005],out[100005];
int tot = 1;

void dfs(int x,int fa)
{
	in[x] = tot ++;
	for (int i = 0; i < g[x].size(); i++)
	{
		int t = g[x][i];
		if( t == fa ) continue;
		dfs(t,x);
	}
	out[x] = tot - 1;
}

题目:给定一棵以1为根的树,有两种操作。操作1将节点的x的权值异或1,操作2询问以x为根的子树的节点权值和。
思路:利用dfs序将子树询问变为区间和,树状数组维护即可。

#include <cstdio>
#include <vector>
using namespace std;

vector<int> g[100005];
int n,num[100005];
int in[100005],out[100005],c[100005];
int tot = 1;

void dfs(int x,int fa)
{
	in[x] = tot ++;
	for (int i = 0; i < g[x].size(); i++)
	{
		int t = g[x][i];
		if( t == fa ) continue;
		dfs(t,x);
	}
	out[x] = tot - 1;
}

int lowbit(int x)
{
	return x & (-x);
}

void update(int x,int k)
{
	for (int i = x; i <= n; i += lowbit(i))
	{
		c[i] += k;
	}
}

int query(int x)
{
	int res = 0;
	for (int i = x; i > 0; i-= lowbit(i))
	{
		res += c[i];
	}
	return res;
}

int main()
{
	scanf("%d",&n); 
	for (int i = 1; i < n; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y); 
	}
	dfs(1);
	for (int i = 1; i <= n; i++)
	{
		update(i,1);
		num[i] = 1;
	} 
	int m;
	scanf("%d",&m);
	for (int i = 1; i <= m; i++)
	{
		getchar();
		char t;
		int x;
		scanf("%c%d",&t,&x);
		if( t == 'Q' )
		{
			printf("%d\n",query(out[x]) - query(in[x]-1));

		}else
		{
			if( num[x] == 0 )
			{
				num[x] = 1;
				update(in[x],1);
			}else
			{
				num[x] = 0;
				update(in[x],-1);
			}
		}
	}
	return 0;
}
发布了132 篇原创文章 · 获赞 6 · 访问量 7914

猜你喜欢

转载自blog.csdn.net/weixin_44316314/article/details/105039262
今日推荐