练习题
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
*/