hdu 6191 Query on A Tree
题意:给一颗根为1的树,每个点有点权,有q次询问,每次询问 u x ,查询 u 子树所有点,和 x 异或最大值是多少。
思路:把每个点权拆成二进制构造字典树,假设每次查找的是 1,x,那么直接从字典树中找最大值(默认这个大家都会),如果是 u,x,那么我只需要只保存 u 子树的字典树,这个时候我们借助dfs序和可持久化操作建字典树,第 i 颗字典树保存字典序 1 到 i 个点的信息,L[ u ]保存 u 节点的dfs序编号,R[ u ]保存 u 子树最大dfs序节点编号,每次查询 u,x,通过rt[ R[u] ] - rt[ L[u] - 1]就可以得到我们想要的字典树,难点解决。
#include <bits/stdc++.h>
using namespace std;
const int maxn= 1e5 + 10 ;
int rt[ maxn] , ls[ maxn* 31 ] , rs[ maxn* 31 ] , sum[ maxn* 31 ] , cnt;
int a[ maxn] , L[ maxn] , R[ maxn] , ID;
vector< int > G[ maxn] ;
void up ( int & o, int pre, int k, int v)
{
o= ++ cnt;
ls[ o] = ls[ pre] ;
rs[ o] = rs[ pre] ;
sum[ o] = sum[ pre] + 1 ;
if ( ! k)
return ;
k-- ;
if ( v& ( 1 << k) )
up ( rs[ o] , rs[ pre] , k, v) ;
else
up ( ls[ o] , ls[ pre] , k, v) ;
}
void dfs ( int u)
{
L[ u] = ++ ID;
up ( rt[ ID] , rt[ ID- 1 ] , 30 , a[ u] ) ;
for ( int i= 0 ; i< G[ u] . size ( ) ; i++ )
dfs ( G[ u] [ i] ) ;
R[ u] = ID;
}
int qu ( int o, int pre, int k, int v)
{
if ( ! k)
return 0 ;
k-- ;
if ( v& ( 1 << k) )
if ( sum[ ls[ o] ] > sum[ ls[ pre] ] )
return ( 1 << k) + qu ( ls[ o] , ls[ pre] , k, v) ;
else
return qu ( rs[ o] , rs[ pre] , k, v) ;
else
if ( sum[ rs[ o] ] > sum[ rs[ pre] ] )
return ( 1 << k) + qu ( rs[ o] , rs[ pre] , k, v) ;
else
return qu ( ls[ o] , ls[ pre] , k, v) ;
}
int main ( )
{
int n, q, u, x, fa;
while ( ~ scanf ( "%d%d" , & n, & q) )
{
for ( int i= 1 ; i<= n; i++ )
scanf ( "%d" , & a[ i] ) ;
for ( int i= 2 ; i<= n; i++ )
{
scanf ( "%d" , & fa) ;
G[ fa] . push_back ( i) ;
}
dfs ( 1 ) ;
while ( q-- )
{
scanf ( "%d%d" , & u, & x) ;
printf ( "%d\n" , qu ( rt[ R[ u] ] , rt[ L[ u] - 1 ] , 30 , x) ) ;
}
for ( int i= 1 ; i<= n; i++ )
G[ i] . clear ( ) ;
for ( int i= 1 ; i<= cnt; i++ )
sum[ i] = ls[ i] = rs[ i] = 0 ;
cnt= ID= 0 ;
}
}
3673: 可持久化并查集 by zky
好困啊,先贴代码睡了…
#include <bits/stdc++.h>
using namespace std;
const int maxn= 4e5 + 10 ;
int n, rt[ maxn] , ls[ maxn* 20 ] , rs[ maxn* 20 ] ;
int sz[ maxn* 20 ] , p[ maxn* 20 ] , cnt;
void build ( int & o, int l, int r)
{
o= ++ cnt;
if ( l== r)
{
p[ o] = l;
sz[ o] = 1 ;
return ;
}
int m= ( l+ r) / 2 ;
build ( ls[ o] , l, m) ;
build ( rs[ o] , m+ 1 , r) ;
}
int query ( int o, int l, int r, int k)
{
if ( l== r)
return o;
int m= ( l+ r) / 2 ;
if ( k<= m)
return query ( ls[ o] , l, m, k) ;
else
return query ( rs[ o] , m+ 1 , r, k) ;
}
int find ( int x, int o)
{
int tmp= query ( o, 1 , n, x) ;
if ( p[ tmp] != x)
return find ( p[ tmp] , o) ;
return tmp;
}
void merge ( int & o, int pre, int l, int r, int k, int v)
{
o= ++ cnt;
ls[ o] = ls[ pre] ;
rs[ o] = rs[ pre] ;
if ( l== r)
{
p[ o] = p[ v] ;
return ;
}
int m= ( l+ r) / 2 ;
if ( k<= m)
merge ( ls[ o] , ls[ pre] , l, m, k, v) ;
else
merge ( rs[ o] , rs[ pre] , m+ 1 , r, k, v) ;
}
void update ( int & o, int pre, int l, int r, int k, int tmp)
{
o= ++ cnt;
ls[ o] = ls[ pre] ;
rs[ o] = rs[ pre] ;
if ( l== r)
{
p[ o] = p[ pre] ;
sz[ o] = sz[ pre] + sz[ tmp] ;
return ;
}
int m= ( l+ r) / 2 ;
if ( k<= m)
update ( ls[ o] , ls[ pre] , l, m, k, tmp) ;
else
update ( rs[ o] , rs[ pre] , m+ 1 , r, k, tmp) ;
}
int main ( )
{
int q, op, x, y, ans= 0 ;
scanf ( "%d%d" , & n, & q) ;
build ( rt[ 0 ] , 1 , n) ;
for ( int i= 1 ; i<= q; i++ )
{
scanf ( "%d%d" , & op, & x) ;
x^ = ans;
if ( op== 1 )
{
scanf ( "%d" , & y) ;
y^ = ans;
rt[ i] = rt[ i- 1 ] ;
int fx= find ( x, rt[ i] ) ;
int fy= find ( y, rt[ i] ) ;
if ( fx!= fy)
{
if ( sz[ fx] > sz[ fy] )
swap ( fx, fy) ;
merge ( rt[ i] , rt[ i] , 1 , n, p[ fx] , fy) ;
update ( rt[ i] , rt[ i] , 1 , n, p[ fy] , fx) ;
}
}
else if ( op== 2 )
rt[ i] = rt[ x] ;
else
{
rt[ i] = rt[ i- 1 ] ;
scanf ( "%d" , & y) ;
y^ = ans;
int fx= find ( x, rt[ i] ) ;
int fy= find ( y, rt[ i] ) ;
if ( fx== fy)
puts ( "1" ) , ans= 1 ;
else
puts ( "0" ) , ans= 0 ;
}
}
}