Bzoj2819 Nim

Description

给定一棵n个节点的无根树,有2种操作:
1、询问x到y的路径上的点权异或和
2、修改某个点的点权

Solution

直接上树剖。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
const int maxn = 500005;
const int INF  = 0x3f3f3f3f;
#define LL long long
struct edge{
    int x,y,next;
    edge(){}
    edge(int _x,int _y,int _nt):x(_x),y(_y),next(_nt){}
}e[maxn << 1];
int head[maxn],tot=0;
int top[maxn],siz[maxn],dep[maxn],p[maxn],son[maxn],fa[maxn];
int n,Q,T,a[maxn],b[maxn];
inline void addedge(int x,int y){
    e[++tot] = edge( x , y , head[x] ); head[x] = tot;
    e[++tot] = edge( y , x , head[y] ); head[y] = tot;
}
void DFS1(int x){
    siz[x] = 1; son[x] = 0;
    for(int y,i = head[x] ; i ; i = e[i].next ){
        y = e[i].y;
        if( dep[y] ) continue;
        dep[y] = dep[x] + 1;
        fa[y] = x;
        DFS1( y );
        siz[x] += siz[y];
        if( siz[y] > siz[son[x]] ) son[x] = y;
    }
}
void DFS2(int x,int chain){
    top[x] = chain;
    p[x] = ++T;
    if( son[x] ) DFS2( son[x] , chain );
    for(int y,i = head[x] ; i ; i = e[i].next ){
        y = e[i].y;
        if( p[y] || son[x] == y ) continue;
        DFS2( y , y );
    }
}

struct node{
    int L,R;
    int sum;
} tree[maxn << 2];
inline void pushup(int p){
    tree[p].sum = tree[p<<1].sum ^ tree[p<<1|1].sum;
}
void build(int p,int L,int R){
    tree[p].L = L; tree[p].R = R;
    if( L == R ) {
        tree[p].sum = a[L];
        return;
    }
    int mid = ( L + R ) >> 1;
    build( p<<1 , L , mid );
    build( p<<1|1 , mid+1 , R );
    pushup( p );
}
void change(int p,int pos,int k){
    int L = tree[p].L, R =tree[p].R;
        if( L == R ) {
        tree[p].sum = k;
        return;
    }
    int mid = ( L + R ) >> 1;
    if( pos <= mid ) change( p<<1 , pos , k );
    else change( p<<1|1 , pos , k );
    pushup( p );
}
int query(int p,int L,int R){
    int n_L = tree[p].L, n_R =tree[p].R;
    if( L <= n_L && n_R <= R ) return tree[p].sum;
    int mid = ( n_L + n_R ) >> 1;
    int sum = 0;
    if( L <= mid ) sum ^= query( p<<1 , L , R );
    if( mid < R ) sum ^= query( p<<1|1 , L , R );
    return sum;
}

void solve_query(int x,int y){
    int sum = 0;
    while( top[x] != top[y] ){
        if( dep[top[x]] < dep[top[y]] ) swap( x , y );
        sum ^= query( 1 , p[top[x]] , p[x] );
        x = fa[top[x]];
    }
    if( dep[x] > dep[y] ) swap( x , y );
    sum ^= query( 1 , p[x] , p[y] );

    puts( sum ? "Yes" : "No" );
}

int main(){
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i++ )
        scanf("%d",&b[i]);
    for(int x,y,i = 1 ; i <= n-1 ; i++ ){
        scanf("%d%d",&x,&y);
        addedge( x , y );
    }
    dep[1] = 1;
    DFS1( 1 );
    DFS2( 1 , 1 );

    for(int i = 1 ; i <= n; i++ )
        a[p[i]] = b[i];
    build( 1 , 1 , n );
    char str[3];int x,y;
    for( scanf("%d",&Q) ; Q ; Q-- ){
        scanf("%s%d%d",str,&x,&y);
        if( str[0] == 'Q' ) solve_query(x,y);
        if( str[0] == 'C' )
            change( 1 , p[x] , y );
    }
}

20s的题跑了19s。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值