【BZOJ】2819: Nim(树链剖分 / lca+dfs序+树状数组)

题目

传送门:QWQ

分析

 先敲了个树链剖分,发现无法AC(其实是自己弱,懒得debug、手写栈)

然后去学了学正解

核心挺好理解的,$ query(a) $是$ a $到根的异或和。

答案就是$ lca(x,y) \hat{}  query(x)  \hat{}  query(b) $

接着维护异或和,很显然线段树挺容易搞的。

但我们今天学学树状数组来维护异或和

若将区间$ [l,r] $内的元素全部异或x,相当于在第l位标记x,再在第r+1位标记x,
这样,对于第r位以后的元素,这两个命令互相抵消,查询某个元素的值,只需用树状数组把它之前的命令全部累加起来即可。

强无敌了~~~ 

代码

lca+dfs序+树状数组:

#include <bits/stdc++.h>
using namespace std;
const int maxn=500005;
int fa[maxn][20],depth[maxn],w[maxn];
int in[maxn],out[maxn],cnt,vis[maxn],n,bit[maxn];
vector<int> G[maxn];
int dfs(int u){
    for(int i=1;i<19;i++){
        if(depth[u] < (1 << i)) break;
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    in[u]=++cnt;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i]; if(vis[v]) continue; vis[v]=1; 
        fa[v][0]=u; depth[v]=depth[u]+1; dfs(v);
    } out[u]=cnt;
}
int lca(int x,int y){
    if(depth[x]<depth[y]) swap(x,y);
    int d=(depth[x]-depth[y]);
    for(int i=0;i<19;i++){ 
        if((1<<i) & d) x=fa[x][i];
    }
    for(int i=18;i>=0;i--){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i]; y=fa[y][i];
        }
    }
    if(x==y) return x;
    else return fa[x][0];
}
void add(int x,int v){for(;x<=n;x+=x&-x) bit[x]^=v;}
int query(int x){int ans=0;for(;x>0;x-=x&-x) ans^=bit[x];return ans;} 
int main()
{
    int u,v,q;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        G[u].push_back(v);G[v].push_back(u);
    }
    vis[1]=1;dfs(1);
    for(int i=1;i<=n;i++){
        add(in[i],w[i]); add(out[i]+1,w[i]);
    }
    scanf("%d",&q);
    int a,b; char s[10];
    while(q--){
        scanf("%s%d%d",s,&a,&b);
        if(s[0]=='Q'){
            int ans=w[lca(a,b)]^query(in[a])^query(in[b]);
            if(ans!=0) puts("Yes");
            else puts("No");
        //    printf("---------------   %d %d %d\n",lca(a,b),query(in[a]),query(in[b]));
        }
        else{
            add(in[a],w[a]);add(out[a]+1,w[a]);
            w[a]=b;
            add(in[a],w[a]);add(out[a]+1,w[a]);
        }
    }
    return 0;
}
/*
8
1 3 5 2 5 3 1 1
1 5
3 5
2 5
1 4
6 3
7 4
8 3
13
Q 1 2
Q 3 5
Q 1 8
Q 3 5
Q 6 2
C 2 5
C 4 6
C 8 5
Q 1 2
Q 3 5
Q 1 8
Q 3 5
Q 6 2
*/ 

树链剖分(无法AC):

#include <bits/stdc++.h>
using namespace std;
const int maxn=500005;
int top[maxn],fa[maxn],son[maxn],dep[maxn],siz[maxn];
int wt[2*maxn],w[2*maxn],id[2*maxn],v[2*maxn],cnt,n;
vector<int> G[maxn];
void build(int o,int l,int r){
    if(l==r){ v[o]=wt[l]; return; }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    v[o]=v[o<<1]^v[o<<1|1];
} 
void update(int o,int l,int r,int val,int L){    
//    printf("--->>>  %d %d %d %d %d\n",o,l,r,val,L);
    if(l==r){
        v[o]=val; return;
    }
    int mid=l+r>>1; 
    if(L<=mid) update(o<<1,l,mid,val,L); 
    else update(o<<1|1,mid+1,r,val,L);
    v[o]=v[o<<1]^v[o<<1|1];
}
int query(int o,int l,int r,int L,int R){
    if(l>R||r<L) return 0;
    if(l>=L&&r<=R){return v[o];}
    int mid=l+r>>1;
    int ans=query(o<<1,l,mid,L,R)^query(o<<1|1,mid+1,r,L,R);
    return ans;
} 
///////////////////////////////////////////
int dfs1(int x,int f,int depth){
    dep[x]=depth; fa[x]=f; siz[x]=1;
    int maxnum=0;
    for(int i=0;i<G[x].size();i++){
        int v=G[x][i];
        if(v==f) continue;
        dfs1(v,x,depth+1);
        siz[x]+=siz[v];
        if(maxnum<siz[v]){
            maxnum=siz[v]; son[x]=v;
        }
    }
}
void dfs2(int x,int topf){
    top[x]=topf; id[x]=++cnt; wt[id[x]]=w[x];
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(int i=0;i<G[x].size();i++){
        int v=G[x][i];
        if(v!=son[x]&&v!=fa[x]){
            dfs2(v,v);
        }
    }
}
void debug(){
    puts("\ndepth: ");
    for(int i=1;i<=n;i++) printf("%d ",dep[i]);
    puts("\nson: ");
    for(int i=1;i<=n;i++) printf("%d ",son[i]);
    puts("\ntop: ");
    for(int i=1;i<=n;i++) printf("%d ",top[i]);
}
int Qu(int x,int y){
    int ans=0;
    for(;top[x]!=top[y];){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans^=query(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]]; 
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans^=query(1,1,n,id[x],id[y]);
    return ans;
} 
int main()
{
//    freopen("1.txt","r",stdin);
    
//    int __size__=30<<20;  
//    char *__p__=(char*)malloc(__size__)+__size__;  
//    __asm__("movl %0, %%esp\n"::"r"(__p__));
    int u,v,q;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        G[u].push_back(v);G[v].push_back(u);
    }
    dfs1(1,0,1); dfs2(1,1);
    build(1,1,n);
    scanf("%d",&q);
//    printf("======   %d\n",query(1,1,n,1,1));
    int a,b; char s[10];
    while(q--){
    //    printf("=========  %d\n",q);
        scanf("%s%d%d",s,&a,&b);
        if(s[0]=='Q'){
            int ans=Qu(a,b);
            if(ans!=0) puts("Yes");
            else puts("No");
        }
        else{
            update(1,1,n,b,id[a]);
        }
    }
//    debug();
    return 0;
}
/*
8
1 3 5 2 5 3 1 1
1 5
3 5
2 5
1 4
6 3
7 4
8 3
13
Q 1 2
Q 3 5
Q 1 8
Q 3 5
Q 6 2
C 2 5
C 4 6
C 8 5
Q 1 2
Q 3 5
Q 1 8
Q 3 5
Q 6 2
*/ 

猜你喜欢

转载自www.cnblogs.com/noblex/p/9136837.html