牛客练习赛58 F

题意

求带单点修改的树上两点间任意子路径长异或和。
路径长等于路径上所有异或和。

题解

简单模拟一下,可以发现。
奇数情况下,答案是偶数点异或和。
偶数情况下,就是正常的异或和。

偶数点异或和也很容易处理。
分深度奇偶树状数组即可。

但是这是对于链的,不能直接 d f s dfs 序,需要剖分一下。
但是我不会,所以去学了一下。

简单意思就是:
孩子结点的子树最大的作为重儿子。
每次优先跑重儿子,可以使得 d f s dfs 序中重链都是连续的。
利用这个特征,我们在处理的时候,每次跳到链头,最后不断处理询问即可。

这其中:树链剖分的复杂度是 n l o g 2 n nlog^2n
不过我还有两点疑问:
为什么复杂度能保证,以及为什么跳的时候要先跳链头深度大的或者 d f s dfs 序大的。

不过目前这不是重点,我就先鸽了(被迫先学了树剖,最近明明在弄图论)

单点更新,三个线段树即可。

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int maxn = 2e5+100;

vector<int>G[maxn];

int sz[maxn],son[maxn],dep[maxn];
int dfn[maxn],top[maxn],fa[maxn];
int A[maxn],cnt,n,m;

//剖分
void dfs1(int u,int pre){
    dep[u]=dep[pre]+1;
    sz[u]=1,fa[u]=pre;
    int s=0;
    for(auto v:G[u]){
        if(v==pre)continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>s)son[u]=v,s=sz[v];
    }
}

void dfs2(int u,int tr_top){
    dfn[u]=++cnt;
    top[u]=tr_top;
    if(son[u])dfs2(son[u],tr_top);
    for(auto v:G[u]){
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}

//树状数组
int C[maxn][3];

int lowbit(int x){return (x&(-x));}
void change(int x,int d,int id){for(int i=x;i<=n;i+=lowbit(i))C[i][id]^=d;}
int query(int x,int id){if(x==0)return 0;int ret=0;for(int i=x;i;i-=lowbit(i))ret^=C[i][id];return ret;}

//树链剖分更新
void update(int x,int c){
    int val=A[x]^c;
    change(dfn[x],val,dep[x]%2);
    change(dfn[x],val,2);
    if(c)A[x]=c;
}

int query(int l,int r,int id){
    int ans=0,now;
    if(dep[l]%2!=dep[r]%2)now=2;
    else now=(dep[l]%2)^1;
    //cout<<id<<"?"<<endl;
    while(top[l]!=top[r]){
        if(dep[l]<dep[r])swap(l,r);
        ans^=query(dfn[l],now)^query(dfn[top[l]]-1,now);
      //  cout<<dfn[l]<<" "<<dfn[top[l]]-1<<endl;
        l=fa[top[l]];
    }
//    cout<<l<<" "<<r<<" "<<dep[l]%2<<" "<<dep[r]%2<<endl;
    if(dfn[l]<=dfn[r])ans^=query(dfn[r],now)^query(dfn[l]-1,now);
    else ans^=query(dfn[l],now)^query(dfn[r]-1,now);
    //cout<<dfn[l]<<" "<<dfn[r]<<endl;
    return ans;
}

int main(){
    cin>>n>>m;
    FOR(i,1,n)scanf("%d",&A[i]);
    FOR(i,1,n-1){
        int u,v;scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,1);
    FOR(i,1,n){
     //   cout<<i<<" "<<fa[i]<<" "<<sz[i]<<" "<<son[i]<<" "<<dep[i]<<" "<<dfn[i]<<" "<<top[i]<<endl;
    }
    FOR(i,1,n)update(i,0);
    FOR(i,1,m){
        int op,l,r;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1)update(l,r);
        else printf("%d\n",query(l,r,i));
    }
    //cout<<dfn[2]<<endl;
   // cout<<query(dfn[2],2)-query(dfn[2]-1,2)<<endl;
}

发布了203 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/104905974