XORTREE(统计树上奇数位路径异或)

题:https://ac.nowcoder.com/acm/problem/200191

题意:给定一棵树,操作一:把u变为x,操作二统计u~v的最短路径中的各子路径的节点的异或和的异或和。1<=n,q<=1e5

分析:考虑一个节点要么被异或到,要么不被异或到,只与被路径选中次数的奇偶有关。

   假设节点从u到v遍历,走过的路径长为x,总路径长为len,那么当前节点被选到的次数就为:x*(len-x)+x+(len-x)=x*(len-x)+len;

   我们发现,当路径长len为奇数的时候,结果肯定为奇数,也就意味着这次询问是询问u~v的节点的异或和;

        当路径长len为偶数的时候,结果是偶奇偶奇。。。地交替,也就意味着这次询问是询问u~v的节点的偶数位的异或和。

   那么可以根据深度的奇偶来判断路径即可,用长链剖分+BIT解决区间异或

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
int read()
{
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x;
}
const int M=2e5+4;
int fa[M],sz[M],deep[M],ans[M],dfn[M],tp[M],son[M],a[M],las[M];
int cnt,n,q;
vector<int>g[M];
struct BIT{
    int tr[3][M];
    void init(){
        memset(tr,0,sizeof(tr));
    }
    void update(int id,int i,int x){
        while(i<=n)
            tr[id][i]^=x,i+=i&(-i);
    }
    int sum(int id,int i){
        int res=0;
        while(i){
            res^=tr[id][i];
            i-=i&(-i);
        }
        return res;
    }
}t1;
void dfs1(int u,int f){
    fa[u]=f,sz[u]=1,deep[u]=deep[f]+1;
    for(auto v:g[u]){
        if(v!=f){
            dfs1(v,u);
            sz[u]+=sz[v];
            if(sz[son[u]]<sz[v])
                son[u]=v;
        }
    }
}
void dfs2(int u,int top){
    tp[u]=top;
    dfn[u]=++cnt;
    if(son[u])
        dfs2(son[u],top);
    for(auto v:g[u]){
        if(v!=fa[u]&&v!=son[u])
            dfs2(v,v);
    }
}
int solve(int u,int v){
    int res=0;
    ///路径长为奇数就,奇数位选,否则,全部选
    int id=( (deep[u]%2==deep[v]%2) ? (1-deep[u]%2) : 2);
    while(tp[u]!=tp[v]){
        if(deep[tp[u]]<deep[tp[v]])
            swap(u,v);
        res^=(t1.sum(id,dfn[u])^t1.sum(id,dfn[tp[u]]-1));
        u=fa[tp[u]];
    }
    if(deep[u]<deep[v])
        swap(u,v);
    res^=(t1.sum(id,dfn[u])^t1.sum(id,dfn[v]-1));
    return res;
}
int main(){
    t1.init();
    n=read(),q=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int u,v,i=1;i<n;i++){
        u=read(),v=read();
        g[u].pb(v),g[v].pb(u);
    }
    dfs1(1,0),dfs2(1,1);
    for(int i=1;i<=n;i++){
        t1.update(deep[i]%2,dfn[i],a[i]);
        t1.update(2,dfn[i],a[i]);
        las[dfn[i]]=a[i];
    }
    while(q--){
        int op=read(),u=read(),v=read();
        if(op==1){
            t1.update(deep[u]%2,dfn[u],las[dfn[u]]^v);
            t1.update(2,dfn[u],las[dfn[u]]^v);
            las[dfn[u]]=v;
        }
        else{
            printf("%d
",solve(u,v));
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13635398.html