JZOJ4843. 相位幻击

题目大意

给定一个 n 个节点的有根树(根节点为1)树。每个点有一个初始的点权。
给出m个操作,每个操作将点 x 的子树全部异或上一个y,或者查询 x,y 路径上的权值异或和。

Data Constraint
n,m200000

题解

直接链剖貌似能碾过去。实际上还有一种更优的解法。
记点 x 到根的路径上的点权异或和为Dist[x]
那么对于询问 (x,y) ,最后答案 Ans=Dist[x] xor Dist[y] xor Dist[LCA(x,y)] xor Dist[fa[LCA(x,y)]]
然后我们可以在DFS序上维护这个Dist,注意到一个修改操作只会对奇偶性相同的深度的点造成影响。所以只要开两个线段树分别维护就可以了。

时间复杂度: O(nlogn)

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;

#define N 500000 + 10
typedef long long ll ;
const int MAXN = 19 ;
struct Tree {
    int sum , tot , del ;
} T[2][4*N] ;

int f[N][MAXN] ;
int Node[N] , Next[N] , Head[N] , tot ;
int W[N] , fa[N] , Dist[N] , Deep[N] ;
int S[N] , DFN[N] , R[N] ;
int n , m , Cnt , ret ;

void link( int u , int v ) {
    Node[++tot] = v ;
    Next[tot] = Head[u] ;
    Head[u] = tot ;
}

void DFS( int x ) {
    DFN[x] = R[x] = ++ Cnt ;
    S[Cnt] = x ;
    for (int p = Head[x] ; p ; p = Next[p] ) {
        if ( Node[p] == fa[x] ) continue ;
        fa[Node[p]] = x ;
        f[Node[p]][0] = x ;
        Dist[Node[p]] = Dist[x] ^ W[Node[p]] ;
        Deep[Node[p]] = Deep[x] + 1 ;
        DFS( Node[p] ) ;
        R[x] = R[Node[p]] ;
    }
}

void Build( int k , int v , int l , int r ) {
    if ( l == r ) {
        T[k][v].sum = Dist[S[l]] ;
        T[k][v].tot = 1 ;
        T[k][v].del = 0 ;
        return ;
    }
    int mid = (l + r) / 2 ;
    Build( k , v + v , l , mid ) ;
    Build( k , v + v + 1 , mid + 1 , r ) ;
    T[k][v].sum = T[k][v+v].sum ^ T[k][v+v+1].sum ;
    T[k][v].tot = T[k][v+v].tot + T[k][v+v+1].tot ;
}

void Update( int k , int v ) {
    if ( !T[k][v].del ) return ;
    int lv = v + v , rv = v + v + 1 ;
    if ( T[k][lv].tot & 1 ) T[k][lv].sum ^= T[k][v].del ;
    if ( T[k][rv].tot & 1 ) T[k][rv].sum ^= T[k][v].del ;
    T[k][lv].del ^= T[k][v].del ;
    T[k][rv].del ^= T[k][v].del ;
    T[k][v].del = 0 ;
}

void ADD( int k , int v , int l , int r , int x , int y , int val ) {
    if ( l == x && r == y ) {
        if ( T[k][v].tot & 1 ) T[k][v].sum ^= val ;
        T[k][v].del ^= val ;
        return ;
    }
    Update( k , v ) ;
    int mid = (l + r) / 2 ;
    if ( y <= mid ) ADD( k , v + v , l , mid , x , y , val ) ;
    else if ( x > mid ) ADD( k , v + v + 1 , mid + 1 , r , x , y , val ) ;
    else {
        ADD( k , v + v , l , mid , x , mid , val ) ;
        ADD( k , v + v + 1 , mid + 1 , r , mid + 1 , y , val ) ;
    }
    T[k][v].sum = T[k][v+v].sum ^ T[k][v+v+1].sum ;
}

void Search( int k , int v , int l , int r , int x ) {
    if ( l == x && r == x ) {
        ret = T[k][v].sum ;
        return ;
    }
    Update( k , v ) ;
    int mid = (l + r) / 2 ;
    if ( x <= mid ) Search( k , v + v , l , mid , x ) ;
    else Search( k , v + v + 1 , mid + 1 , r , x ) ;
    T[k][v].sum = T[k][v+v].sum ^ T[k][v+v+1].sum ;
}

void Pre() {
    for (int j = 1 ; j < MAXN ; j ++ ) {
        for (int i = 1 ; i <= n ; i ++ ) f[i][j] = f[f[i][j-1]][j-1] ;
    }
    Build( 0 , 1 , 1 , n ) ;
    Build( 1 , 1 , 1 , n ) ;
}

int Find( int x ) {
    if ( !x ) return 0 ;
    int k = Deep[x] & 1 ;
    ret = 0 ;
    Search( k , 1 , 1 , n , DFN[x] ) ;
    return ret ;
}

int LCA( int x , int y ) {
    if ( Deep[x] < Deep[y] ) swap( x , y ) ;
    for (int i = MAXN - 1 ; i >= 0 ; i -- ) {
        if ( Deep[f[x][i]] >= Deep[y] ) x = f[x][i] ;
    }
    if ( x == y ) return x ;
    for (int i = MAXN - 1 ; i >= 0 ; i -- ) {
        if ( f[x][i] != f[y][i] ) x = f[x][i] , y = f[y][i] ;
    }
    return f[x][0] ;
}

int main() {
    freopen( "phase.in" , "r" , stdin ) ;
    freopen( "phase.out" , "w" , stdout ) ;
    scanf( "%d" , &n ) ;
    for (int i = 1 ; i < n ; i ++ ) {
        int u , v ;
        scanf( "%d%d" , &u , &v ) ;
        link( u , v ) ;
        link( v , u ) ;
    }
    for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &W[i] ) ;
    scanf( "%d" , &m ) ;
    Deep[1] = 1 ;
    Dist[1] = W[1] ;
    DFS( 1 ) ;
    Pre() ;
    for (int i = 1 ; i <= m ; i ++ ) {
        char op ;
        int x , y ;
        scanf( "\n%c %d %d" , &op , &x , &y ) ;
        if ( op == 'C' ) {
            int k = Deep[x] & 1 ;
            ADD( k , 1 , 1 , n , DFN[x] , R[x] , y ) ;
        }
        else {
            int ans = Find(x) ^ Find(y) ;
            int L = LCA( x , y ) ;
            ans = ans ^ Find(L) ^ Find(fa[L]) ;
            printf( "%d\n" , ans ) ;

        }
    }
    return 0 ;
}

以上.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值