2017广西邀请赛 Query on A Tree(可持久化字典树)


题意:给你一棵树,每个节点一个权值,然后m次查询,每次查询以u为根节点的子树上的某点与x异或的最大值。

题解:比赛时死活不会写,当时没学可持久化字典树,暴力写了一发,然后无限TLE。。。其实就是一道可持久化字典树模板题,我们可以将树上的权值转化为区间问题,呢就用DFS序好了,剩下的跑一发可持久化字典树就OK了。

#include<set>
#include<map>       
#include<stack>              
#include<queue>              
#include<vector>      
#include<string>    
#include<math.h>     
#include<stdio.h>              
#include<iostream>              
#include<string.h>              
#include<stdlib.h>      
#include<algorithm>     
#include<functional>      
using namespace std;    
typedef long long ll;
#define inf  1000000000         
#define mod 1000000007               
#define maxn  260005   
#define PI acos(-1.0) 
#define lowbit(x) (x&-x)                          
#define eps 1e-9  
vector<int>q[maxn];
int n, m, t, a[maxn], id[maxn], rt[maxn], st[maxn], ed[maxn], b[maxn];
struct node
{
	int cnt;
	int ch[maxn * 32][2], sum[maxn * 32];
	void init()
	{
		cnt = 0;b[0] = 1;
		for (int i = 1;i <= 30;i++)
			b[i] = b[i - 1] * 2;
		memset(ch, 0, sizeof(ch));
		memset(sum, 0, sizeof(sum));
	}
	int insert(int x, int val)
	{
		int res, y;
		y = res = ++cnt;
		for (int i = 30;i >= 0;i--)
		{
			ch[y][0] = ch[x][0];
			ch[y][1] = ch[x][1];
			sum[y] = sum[x] + 1;
			int tmp = val&b[i];
			tmp >>= i;x = ch[x][tmp];
			ch[y][tmp] = ++cnt;y = ch[y][tmp];
		}
		sum[y] = sum[x] + 1;
		return res;
	}
	int query(int l, int r, int val)
	{
		int ans = 0;
		for (int i = 30;i >= 0;i--)
		{
			int tmp = val&b[i];
			tmp >>= i;
			if (sum[ch[r][tmp ^ 1]] - sum[ch[l][tmp ^ 1]])
				ans += b[i], l = ch[l][tmp ^ 1], r = ch[r][tmp ^ 1];
			else
				l = ch[l][tmp], r = ch[r][tmp];
		}
		return ans;
	}
}trie;
void dfs(int u, int p)
{
	st[u] = ++t;
	id[t] = u;
	for (int i = 0;i < q[u].size();i++)
	{
		int v = q[u][i];
		if (v == p)
			continue;
		dfs(v, u);
	}
	ed[u] = t;
}
int main(void)
{
	int i, j, x;
	while (scanf("%d%d", &n, &m) != EOF)
	{
		t = 0;rt[0] = 0;
		trie.init();
		for (i = 1;i <= n;i++)
			scanf("%d", &a[i]), q[i].clear();
		for (i = 2;i <= n;i++)
		{
			scanf("%d", &x);
			q[x].push_back(i);
		}
		dfs(1, 0);
		for (i = 1;i <= n;i++)
			rt[i] = trie.insert(rt[i - 1], a[id[i]]);
		int l, r, root, x;
		while (m--)
		{
			scanf("%d%d", &root, &x);
			l = st[root];r = ed[root];
			printf("%d\n", trie.query(rt[l - 1], rt[r], x));
		}
	}
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值