Trie树练习题 启发式合并

练习题

Time Limit: 2 Sec  
Memory Limit: 256 MB

Description

  有一棵树,每一个点有一个权值,对于每一个点,求出子树路径最大异或和(就是这条路上所有节点权值异或和)

Input

  第一行有两个n,表示节点数。 接下来n个数,表示权值。n-1行,边

Output

  一行n个数

Sample Input

5
1775 6503 8147 2354 8484
1 2
1 3
3 4
1 5

Sample Output

16044 6503 8147 2354 8484

HINT

数据范围:1e5

Source

    by  mhy12345
这道题我就是做不出来,没有写过trie树上求最大异或和(虽然现在看来很简单)
因为这道题题解没说清楚,所以我是看的std的(想不相似也难,毕竟看了std)
对于每一个点,我们对于它建一棵trie树
遍历时,对于每一个子节点,我们启发式合并
先提出小的trie树的所有数,查询一下再顺便更新答案
再插入(保证了lca是这个点)
就完了(现在看来很简单,然而当时不会做)
注意点
回收点的编号,最大空间是nlogn*2(trie树是nlogn的,同时我们是先询问再插入的)

#include <bits/stdc++.h>
#define pa pair<int,int>
using namespace std;
const int N = 100000 + 5;
int last[N],cnt,v[N],sum[N],siz[N],n;
struct Edge{ int to,next; }e[N<<1];
void insert( int u, int v ){
	e[++cnt].to = v; e[cnt].next = last[u]; last[u] = cnt;
	e[++cnt].to = u; e[cnt].next = last[v]; last[v] = cnt;
}
void dfs( int x, int f ){
	siz[x] = 1; sum[x] ^= v[x];
	for( int i = last[x]; i; i = e[i].next )
		if( e[i].to ^ f ){
			sum[e[i].to] = sum[x];
			dfs( e[i].to, x );
			siz[x] += siz[e[i].to];
		}
}
//不会trie区间异或和
struct node{
	int c[2],siz;
}t[N*40];
int rub[N*40],tail,root[N],ans[N];
void ins( int &k, int x, int dep ){
	if( !k ){ k = rub[tail--]; t[k] = t[0]; }
	t[k].siz++; if( dep == -1 ) return ;
	if( x & (1<<dep) ) ins( t[k].c[1], x, dep-1 );
	else ins( t[k].c[0], x, dep-1 );
}
int find( int k, int x, int dep ){
	if( dep == -1 ) return 0;
	if( x & (1<<dep) ){
		if( t[k].c[0] ) return find( t[k].c[0], x, dep-1 ) + ( 1<<dep );
		else return find( t[k].c[1], x, dep-1 );
	}else{
		if( t[k].c[1] ) return find( t[k].c[1], x, dep-1 ) + ( 1<<dep );
		else return find( t[k].c[0], x, dep-1 );
	}
}
void get_que( int k, vector<int> &q, int x, int dep ){
	if( !k ) return ;
	if( dep == -1 ) q.push_back(x);
	rub[++tail] = k;
	get_que( t[k].c[0], q, x, dep-1 );
	get_que( t[k].c[1], q, x+(1<<dep), dep-1 );
}
pa merge( int a, int b, int val ){
	pa ret = make_pair(0,0);
	if( t[a].siz < t[b].siz ) swap( a, b );
	vector <int> que;
	get_que( b, que, 0, 30 );
	for( int i = 0; i < (int)que.size(); i++ )
		ret.second = max( ret.second, find( a, que[i]^val, 30 ) );
	for( int i = 0; i < (int)que.size(); i++ ) ins( a, que[i], 30 );
	ret.first = a;
	return ret;
}
void dfs2( int x, int f ){
	int now = root[x]; ans[x] = v[x];
	for( int i = last[x]; i; i = e[i].next )
		if( e[i].to ^ f ){
			dfs2( e[i].to, x );/**/
			pa ret = merge( now, root[e[i].to], v[x] );
			ans[x] = max( ans[x], ret.second );
			root[e[i].to] = 0; now = ret.first;
		}
	root[x] = now;
}
int main(){
	freopen("irregular.in","r",stdin);
	freopen("irregular.out","w",stdout);
	cin>>n;
	for( int i = 1; i <= n; i++ ) scanf( "%d", &v[i] );
	for( int i = 1, u, v; i < n; i++ ){
		scanf( "%d%d", &u, &v );
		insert( u, v );
	}
	dfs( 1, 0 );
	for( int i = 1; i < N*40; i++ ) rub[++tail] = i;
	for( int i = 1; i <= n; i++ ) ins( root[i], sum[i], 30 );
	dfs2( 1, 0 );
	for( int i = 1; i <= n; i++ ) printf( "%d ", ans[i] );
	return 0;
}
/*
5
1775 6503 8147 2354 8484
1 2
1 3
3 4
1 5
*/
    原文作者:Trie树
    原文地址: https://blog.csdn.net/youhavepeople/article/details/78115162
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注