题目
题解&思路
首先不难发现只有|1与&0是对答案有贡献的,如果这道题把每一位拆开来做就会变得很简单,直接线段树维护一下即可,可是如果要求合并起来做就需要其它思路。自己的思路开始是想用一个lazy标记,虽然这样lazy确实可以合并,也可以进行pushdown,但是算异或值的时候就很麻烦,不知道这一位的0或1是强制覆盖还是按原来的。
正解
用两个lazy标记,lazy0表示如果这一位上有1,则这一位区间强制覆盖为1,lazy0表示如果这一位上有0,则这一位区间强制覆盖为0,那么modify的时候就需要同时改lazy0,lazy1,且pushdown的时候注意现在的lazy1对之前的lazy0,lazy1都是有影响的
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e5 + 3;
const ll inf = ( 1 << 31 ) - 1;
int n , m , head[MAXN] , cnt , ncnt , id[MAXN] , top[MAXN] , dep[MAXN] , zson[MAXN] , siz[MAXN] , fd[MAXN];
struct node{
int l , r ;
ll zhi , lazy0 , lazy1;
}tre[MAXN<<2];
ll yh[MAXN];
struct edge{
int next , v;
}G[MAXN<<1];
inline void add_edge( int x , int y ){
G[cnt].next = head[x];
G[cnt].v = y;
head[x] = cnt ++;
}
int fa[MAXN];
inline void dfs( int x, int f ){
siz[x] = 1;
for( int i = head[x] ; i != -1 ; i = G[i].next ){
int v = G[i].v;
if( v == f) continue;
dep[v] = dep[x] + 1;
fa[v] = x;
dfs( v , x );
siz[x] += siz[v];
if( !zson[x] || siz[zson[x]] < siz[v] ) zson[x] = v;
}
}
inline void dfs1( int x, int f ){
top[x] = f;
id[x] = ++ncnt;
fd[ncnt] = x;
if( !zson[x] ) return;
dfs1( zson[x] , f );
for( int i = head[x] ; i != -1 ; i = G[i].next ){
int v = G[i].v;
if( v == fa[x] || v == zson[x] ) continue;
dfs1( v , v );
}
}
inline void huo( node &x , ll delta ){
int p = dep[fd[x.r]] - dep[fd[x.l]] + 1;
for( int j = 0 ; j < 30 ; j ++ ){
if( ( delta & ( 1ll << j ) ) && (p & 1) )
x.zhi |= ( 1ll << j );
else if( ( delta & ( 1 << j ) ) && !(p & 1) )
x.zhi &= (~( 1ll << j ));
}
}
inline void qie( node &x ,ll delta ){
for( int j = 0 ; j < 30 ; j ++ ){
if( !( delta & ( 1ll << j ) ) )
x.zhi &= (~(1ll<<j) );
}
}
inline void build( int i , int l , int r ){
tre[i].l = l , tre[i].r = r;
tre[i].lazy0 = 0 , tre[i].lazy1 = inf;
if( l == r ){
tre[i].zhi = yh[fd[l]];
return ;
}
int mid = ( l + r ) >> 1;
build( i << 1 , l , mid );
build( i << 1 | 1 , mid + 1, r );
tre[i].zhi = tre[i<<1].zhi ^ tre[i<<1|1].zhi;
}
inline void pushdown( int i ){// lazy0 | lazy1 &
if( tre[i].lazy1 != inf ){ tre[i<<1].lazy0 &= tre[i].lazy1 , tre[i<<1|1].lazy0 &= tre[i].lazy1;}
if( tre[i].lazy0 ) { tre[i<<1].lazy1 |= tre[i].lazy0 , tre[i<<1|1].lazy1 |= tre[i].lazy0; }
if( tre[i].lazy0 ){
tre[i<<1].lazy0 |= tre[i].lazy0 , tre[i<<1|1].lazy0 |= tre[i].lazy0;
huo( tre[i<<1] , tre[i].lazy0 );
huo( tre[i<<1|1] , tre[i].lazy0 );
tre[i].lazy0 = 0;
}
if( tre[i].lazy1 != inf ){
tre[i<<1].lazy1 &= tre[i].lazy1 , tre[i<<1|1].lazy1 &= tre[i].lazy1;
qie( tre[i<<1] , tre[i].lazy1 );
qie( tre[i<<1|1] , tre[i].lazy1 );
tre[i].lazy1 = inf;
}
}
inline void modify( int i , int l , int r , ll delta , int flag ){
if( tre[i].l > r || tre[i].r < l )
return ;
if( tre[i].l >= l && tre[i].r <= r ){
if( flag == 1 ){
tre[i].lazy0 |= delta;
tre[i].lazy1 |= delta;
huo( tre[i] , delta );
}
else{
tre[i].lazy0 &= delta;
tre[i].lazy1 &= delta;
qie( tre[i] , delta );
}
return ;
}
pushdown( i );
modify( i << 1 , l , r , delta , flag );
modify( i << 1 | 1 , l , r, delta , flag );
tre[i].zhi = tre[i<<1].zhi ^ tre[i<<1|1].zhi;
}
inline ll query( int i , int l , int r ){
if( tre[i].l > r || tre[i].r < l )
return 0;
if( tre[i].l >= l && tre[i].r <= r ){
return tre[i].zhi;
}
pushdown( i );
ll ans = query( i << 1 , l , r );
ans ^= query( i << 1 | 1 , l , r );
tre[i].zhi = tre[i<<1].zhi ^ tre[i<<1|1].zhi;
return ans;
}
inline void change( int x , ll z , int op ){
while( top[x] != top[1] ){
modify( 1 , id[top[x]] , id[x] , z , op );
x = fa[top[x]];
}
modify( 1 , id[1] , id[x] , z , op );
}
inline void get_ans( int x , ll z ){
ll ans = 0;
while( top[x] != top[1] ){
ans ^= query( 1 , id[top[x]] , id[x] );
x = fa[top[x]];
}
ans ^= query( 1 , id[1] , id[x] );
if( ans ^ z ){
printf( "YES\n" );
return ;
}
printf( "NO\n" );
}
int main(){
scanf( "%d%d" , &n , &m );
for( int i = 1 ; i <= n ;i ++ ) scanf( "%lld" , &yh[i] );
for( int i = 1 ; i <= n ; i ++ ) head[i] = -1;
for( int i = 1 ; i < n ; i ++ ){
int x , y;scanf( "%d%d" , &x , &y );
add_edge( x , y );
add_edge( y , x );
}
dep[1] = 1;
dfs( 1 , 0 );
dfs1( 1 , 1 );
build( 1 , 1 , n );
for( int i = 1 ; i <= m ; i ++ ){
int x , y ;
ll z;
scanf( "%d%d%lld" , &x , &y , &z );
if( x < 3){
change( y , z , x );
}
else{
get_ans( y , z );
}
}
return 0;
}