天天看点

hdu 3974 Assign the task (线段树)

错误总结:

这一题没有1A,主要原因是有点累,在敲代码的过程中注意力有些无法集中起来。

最后导致在调用函数的地方传参数传错了!!!检查的时候只把函数认真看了一遍,而调用函数的地方却漏看了!!!!以后要注意!

题目大意:

给一个有根数,然后有以下两种操作。

操作一:T X Y ,将以X为根的子树上的所有节点都变成Y

操作二:C X,查询第X号点是多少?

这一题初看是一道维护树型结构的题,但它更新的是整颗子树的值,所以可以转化成DFS序后用线段树来维护。

具体如下:

一开始给定了这样一棵树

          2

        /     \

      3       5

    /    \

  4      1

转化成DFS序:2344113552(这个可以DFS求出)

然后记录下每个数字最左边和最右边的位置,如:left[3] = 2,  right[3] = 7。

因为DFS序的性质,x的所有子节点i,都满足left[i]∈[left[x], right[x]] 和 right[i]∈[left[x], right[x]]

所以操作一和操作二就可以转换到DFS序上进行。

操作一:

updata(p_left[x], p_right[x], 1, val, i);
           

操作二:

query(p_left[x], 1);
           

这一题就变成了。区间赋值修改和单点查询,所以考虑使用线段树来维护。

(这一题好像只要直接做用最简单线段树维护就好了,即如果能够包含整段节点区间就直接更新这个节点的值,否则就将该节点的值传递到他的左右子节点,然后递归到左右子节点进行操作。。。一开始脑抽了,以为会退化以至于超时。。。。)

所以我才用了别的方法。

我在每个线段树节点中除了有一个num值记录改节点的值,还有一个time值记录该节点的值是在第几次操作中被修改的。

class node
{
	public:
		int x, y, num, time;
};
           

所以这样就不需要考虑把节点的值传递给其左右自由节点。只要直接维护线段树的Num和time值就好了。

void updata(int x, int y, int t, int val, int time)
{
	if (a[t].x > y || a[t].y < x)
		return;
	if (x <= a[t].x && a[t].y <= y)
	{
		a[t].num = val;
		a[t].time = time;
		return;
	}
	updata(x, y, t*2, val, time);
	updata(x, y, t*2+1, val, time);
}
           

然后查询的时候就输出,所有包含x的节点中time值最大的那个节点的num值(好绕。。。。)

void query(int pos, int t)
{
	if (pos > a[t].y || pos < a[t].x)
		return;
	if (a[t].time > ans_time)
	{
		ans_time = a[t].time;
		ans = a[t].num;
	}
	if (a[t].x != a[t].y)
	{
		query(pos, t*2);
		query(pos, t*2+1);
	}
	return;
}
           

最后贴上我的全部代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;

class node
{
	public:
		int x, y, num, time;
};
const int MAXN = 6e4;

vector <int> v[MAXN];
int pos[MAXN*2], p_left[MAXN], p_right[MAXN];
node a[5*MAXN];
int n, index, m, ans, ans_time;

void build(int x, int y, int t)
{
	int mid;
	a[t].x = x;
	a[t].y = y;
	a[t].time = 0;
	a[t].num = -1;
	if (x != y)
	{
		mid = (x + y) / 2;
		build(x, mid, t*2);
		build(mid+1, y, t*2+1);
	}
	return;
}
void query(int pos, int t)
{
	if (pos > a[t].y || pos < a[t].x)
		return;
	if (a[t].time > ans_time)
	{
		ans_time = a[t].time;
		ans = a[t].num;
	}
	if (a[t].x != a[t].y)
	{
		query(pos, t*2);
		query(pos, t*2+1);
	}
	return;
}
void updata(int x, int y, int t, int val, int time)
{
	if (a[t].x > y || a[t].y < x)
		return;
	if (x <= a[t].x && a[t].y <= y)
	{
		a[t].num = val;
		a[t].time = time;
		return;
	}
	updata(x, y, t*2, val, time);
	updata(x, y, t*2+1, val, time);
}
void dfs(int x)
{
	int i;
	index ++;
	pos[index] = x;
	p_left[x] = index;
	for (i=0; i<v[x].size(); i++)
		dfs(v[x][i]);
	index ++;
	pos[index] = x;
	p_right[x] = index;
	return;
}
int main()
{
	int T, tt, i, x, y, root, val;
	char c;
	scanf("%d",&T);
	tt = 0;
	while (T--)
	{
		tt++;
		scanf("%d",&n);
		root = 0;
		for (i = 1; i <= n; i++)
		{
			v[i].clear();
			root = root ^ i;
		}
		for (i = 1; i < n; i ++)
		{
			scanf("%d%d",&x,&y);
			v[y].push_back(x);
			root = root ^ x;
		}
		index = 0;
		dfs(root);
		build(1, 2*n, 1);
		printf("Case #%d:\n", tt);
		scanf("%d",&m);
		for (i=1; i<=m; i++)
		{
			scanf("%c",&c);
			while (c != 'T' && c != 'C')
				scanf("%c",&c);
	//		cout << c << endl;
			if (c == 'C')
			{
				scanf("%d",&x);
				ans_time = 0;
				ans = -1;
				query(p_left[x], 1);
				printf("%d\n", ans);
			}
			else if (c == 'T')
			{
				scanf("%d%d",&x,&val);
			//	cout << p_left[x] << ' ' << p_right[x] << endl;
				updata(p_left[x], p_right[x], 1, val, i);
			}
		}
	}
	return 0;
}