牛客练习赛58 F XOR TREE - 树链剖分

考虑到异或两次就会相消

经过分析发现

  • 如果路径的长度是奇数个点,那么等效于所有偶数次序的点被记录一次
  • 如果路径长度是偶数个点,那么所有点都被计入一次

考虑到次序这个东西可以用深度相邻黑白染色来实现,我们把树拆成两份,黑色一份,白色一份

黑色树上只记录黑色点的权值,白色点权值全部为零,白色树反之

偷懒直接上树链剖分,最后记得处理一下 LCA 上的答案

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
vector <int> g[N];
int n,m,a[N],t1,t2,t3;
int fa[N],siz[N],f[N],dep[N],wson[N],dfn[N],top[N],ind,tot;

void dfs1(int p) {
    siz[p]=1;
    for(int q:g[p]) {
        if(q==fa[p]) continue;
        fa[q]=p;
        dep[q]=dep[p]+1;
        dfs1(q);
        siz[p]+=siz[q];
        if(siz[q]>siz[wson[p]]) wson[p]=q;
    }
}

void dfs2(int p) {
    dfn[p]=++ind;
    if(wson[p]) {
        top[wson[p]]=top[p];
        dfs2(wson[p]);
    }
    for(int q:g[p]) {
        if(q==fa[p]) continue;
        if(q==wson[p]) continue;
        top[q]=q;
        dfs2(q);
    }
}

struct tree {
    int a[1000005];
    void modify(int p,int l,int r,int pos,int key) {
        if(l==r) a[p]=key;
        else {
            if(pos<=(l+r)/2) modify(p*2,l,(l+r)/2,pos,key);
            else modify(p*2+1,(l+r)/2+1,r,pos,key);
            a[p]=a[p*2]^a[p*2+1];
        }
    }
    int query(int p,int l,int r,int ql,int qr) {
        if(l>qr || r<ql) return 0;
        if(l>=ql&&r<=qr) return a[p];
        return query(p*2,l,(l+r)/2,ql,qr)^query(p*2+1,(l+r)/2+1,r,ql,qr);
    }
    int lca(int x,int y) {
        for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
        return dep[x]<dep[y]?x:y;
    }
    int dist(int x,int y) {
        int l=lca(x,y);
        return dep[x]+dep[y]-2*dep[l];
    }
    void tmodify(int p,int key) {
        modify(1,1,n,dfn[p],key);
    }
    int lquery(int p) {
        int ans=0;
        while(p) {
            int t=top[p];
            ans^=query(1,1,n,dfn[t],dfn[p]);
            p=fa[t];
        }
        return ans;
    }
    int tquery(int p,int q) {
        int l=lca(p,q);
        int ans=query(1,1,n,dfn[l],dfn[l]);
        ans^=lquery(p);
        ans^=lquery(q);
        return ans;
    }
} A,B;

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
    }
    for(int i=1;i<n;i++) {
        cin>>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    dep[1]=1;
    dfs1(1);
    top[1]=1;
    dfs2(1);
    for(int i=1;i<=n;i++) {
        if(dep[i]&1) A.tmodify(i,a[i]);
        else B.tmodify(i,a[i]);
    }
    for(int i=1;i<=m;i++) {
        cin>>t1>>t2>>t3;
        if(t1==1) {
            a[t2]=t3;
            if(dep[t2]&1) A.tmodify(t2,a[t2]);
            else B.tmodify(t2,a[t2]);
        }
        else {
            int d=A.dist(t2,t3);
            if(d%2==0) {
                if(dep[t2]&1) {
                    cout<<B.tquery(t2,t3)<<endl;
                }
                else {
                    cout<<A.tquery(t2,t3)<<endl;
                }
            }
            else {
                cout<<(A.tquery(t2,t3)^B.tquery(t2,t3))<<endl;
            }
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12380636.html