HDU5390 tree dfs序+线段树分层离线+字典树求异或最大值

tree

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)


Problem Description
Given a rooted tree(node 1 is the root) with n nodes. The ithnode has a positive value vi at beginning.
We define the universal set S includes all nodes.
There are two types of Memphis's operation.
First, Memphis may change the value of one node. It's the first type operation:
0  u  v   (uS,0v109)

What's more, Memphis wants to know what's the maxinum of vuvt(tpath(u,root),  means  xor) . It's the second type operation:
1  u   (uS)
 


Input
This problem has multi test cases(no more than 3).
The first line contains a single integer T, which denotes the number of test cases.
For each test case,the first line contains two non-negative integer n,m(1n,m100000) - the number of nodes and operations.
The second line contains n1 non-negative integer f2fn(fi<i) - the father of ithnode.
The third line contains n non-negative integer v1vn(0vi109) - the value of nodes at beginning.
Follow m lines describe each operation.
 


Output
For each test cases,for each second operation print a non-negative integer.
 


Sample Input
 
   
1 10 10 1 1 2 2 3 1 2 3 5 23512 460943 835901 491571 399045 97756 413210 800843 283274 106134 0 7 369164 0 7 296167 0 6 488033 0 7 187367 0 9 734984 1 6 0 5 329287 1 5 0 7 798656 1 10
 


Sample Output
 
   
766812 351647 431641
 


Author
SXYZ
 


Source
2015 Multi-University Training Contest 8

题意:给定一个数,根节点为1,每个点有一个点权。有两个操作,0操作是询问某点的点权与这个点到根的路径上的点的点权的异或的最大值。1操作是修改某个点的点权。

思路:求在集合中查找异或的最大值,想到的是使用字典树。用线段树按照dfs序建树,某个点的权值将对其区间内(子树)的点的询问造成影响,所以点权修改就是对其覆盖的区间上的字典树进行修改。询问就是从这个点的dfs序在线段树内的节点往上走,在经过的每个线段树节点的字典树内查询,让后取最大值。

上面做法的在时间上是可行的,但是会MLE。我们采取按线段树分层的办法。从线段树最下层开始,对于每一个操作,得到这个操作在这一层对应的区间,然后进行操作或者询问,没有就不操作。最后询问的结果依然是这个点在每层询问中的最大值。

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include
#include
#include
#include
#define maxn 100005
using namespace std;
struct OP
{
	int op, id, x;
}op[maxn];
struct Seg
{
	int l, r;
	int root;
	Seg() {}
	Seg(int _l, int _r, int _ro)
	{
		l = _l;
		r = _r;
		root = _ro;
	}
};
vector T[20];
void build(int L, int R, int dep)
{
	T[dep].push_back(Seg(L, R, 0));
	if (L != R)
	{
		int mid = L + R >> 1;
		build(L, mid, dep + 1);
		build(mid + 1, R, dep + 1);
	}
}
int ch[4000000][2];
int num[4000000];
int cnt;
void insert_Dic(int root, int x)
{
	num[root]++;
	for (int i = 30; i >= 0; i--)
	{
		int c = (x&(1 << i)) ? 1 : 0;
		if (!ch[root][c]) ch[root][c] = ++cnt;
		root = ch[root][c];
		num[root]++;
	}
}
void erase_Dic(int root, int x)
{
	num[root]--;
	for (int i = 30; i >= 0; i--)
	{
		int c = (x&(1 << i)) ? 1 : 0;
		root = ch[root][c];
		num[root]--;
	}
}
int find_Dic(int root, int x)
{
	int res = 0;
	for (int i = 30; i >= 0; i--)
	{
		int c = (x&(1 << i)) ? 1 : 0;
		if (ch[root][c ^ 1] && num[ch[root][c ^ 1]])
		{
			res |= 1 << i;
			root = ch[root][c ^ 1];
		}
		else root = ch[root][c];
	}
	return res;
}
vector Q;
void Select(int L, int R, int l, int r, int dep, int deep)
{
	if (dep > deep) return;
	if (l <= L&&R <= r)
	{
		if(dep==deep)
			Q.push_back(Seg(L, R, 0));
	}
	else
	{
		int mid = L + R >> 1;
		if (l <= mid) Select(L, mid, l, r, dep + 1, deep);
		if (mid < r) Select(mid + 1, R, l, r, dep + 1, deep);
	}
}
struct EDGE
{
	int to, next;
	EDGE() {}
	EDGE(int _t, int _n) { to = _t, next = _n; }
}edge[maxn];
int head[maxn], edgecnt;
void init_edge()
{
	memset(head, -1, sizeof(head));
	edgecnt = 0;
}
void add(int s, int t)
{
	edge[edgecnt] = EDGE(t, head[s]);
	head[s] = edgecnt++;
}
int dfs_clk;
int Left[maxn], Right[maxn];
void dfs(int u)
{
	Left[u] = ++dfs_clk;
	for (int i = head[u]; ~i; i = edge[i].next)
		dfs(edge[i].to);
	Right[u] = dfs_clk;
}
int val[maxn], _val[maxn];
int ans[maxn];
int bin(int idx, int x)
{
	int L = 0, R = T[idx].size();
	while (L < R)
	{
		int mid = (L + R) >> 1;
		if (T[idx][mid].l <= x) L = mid + 1;
		else R = mid;
	}
	return L - 1;
}
int main()
{
	int Ts;
	scanf("%d", &Ts);
	while (Ts--)
	{
		init_edge();
		int n, m;
		scanf("%d %d", &n, &m);
		for (int i = 2; i <= n; i++)
		{
			int fa;
			scanf("%d", &fa);
			add(fa, i);
		}
		dfs_clk = 0;
		dfs(1);
		for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
		int Qc = 0;
		for (int i = 1; i <= m; i++)
		{
			scanf("%d %d", &op[i].op, &op[i].id);
			if (op[i].op == 0) scanf("%d", &op[i].x);
			else Qc++;
		}
		for (int i = 0; i < 20; i++) T[i].clear();
		build(1, dfs_clk, 0);
		memset(ans, 0, sizeof(ans));
		for (int i = 19; i >= 0; i--)
			if (T[i].size())
			{
				int Tsize = T[i].size();
				memcpy(_val, val, sizeof(_val));
				memset(ch, 0, sizeof(ch));
				memset(num, 0, sizeof(num));
				cnt = 0;
				for (int j = 0; j < Tsize; j++) T[i][j].root = ++cnt;
				for (int j = 1; j <= n; j++)
				{
					Q.clear();
					Select(1, dfs_clk, Left[j], Right[j], 0, i);
					for (int k = 0; k < Q.size(); k++)
					{
						int pos = bin(i, Q[k].l);
						insert_Dic(T[i][pos].root, _val[j]);
					}
				}
				int quecnt = 0;
				for (int j = 1; j <= m;j++)
					if (op[j].op == 0)
					{
						Q.clear();
						Select(1, dfs_clk, Left[op[j].id], Right[op[j].id], 0, i);
						for (int k = 0; k < Q.size(); k++)
						{
							int pos = bin(i, Q[k].l);
							erase_Dic(T[i][pos].root, _val[op[j].id]);
							insert_Dic(T[i][pos].root, op[j].x);
						}
						_val[op[j].id] = op[j].x;
					}
					else
					{
						quecnt++;
						int pos = bin(i, Left[op[j].id]);
						if (pos >= 0 && T[i][pos].l <= Left[op[j].id] && Left[op[j].id] <= T[i][pos].r)
						{
							ans[quecnt] = max(ans[quecnt], find_Dic(T[i][pos].root, _val[op[j].id]));
						}
					}
			}
		for (int i = 1; i <= Qc; i++) printf("%d\n", ans[i]);
	}
	return 0;
}



你可能感兴趣的:(数据结构)