luogu 5556

luguo 5556 剑圣护符

1 题目描述

2 分析

  • 由于点的权值小于\(2^{30}\),所以对于超过30个数字,一定可以存在异或为0的情况。所以对于每个询问,如果x到y之间的节点个数超过30的,答案一定是YES。对于小于等于30个数字,我们可以暴力建立线性基,如果有一个数不能插入线性基,答案也是YES,如果所有的数都能插入线性基,那么答案是NO。
  • 如何修改呢? 由于是修改路径,所以我们可以进行树链剖分,问题转换为区间修改,单点查询。这个可以用线段树或者带差分的树状数组来做,我写了一个树状数组。
  • 时间复杂度:\(O(n\log_{2}^{2}{n})\),本题的主要时间复杂度在于树链剖分。

3 代码

  • #include<bits/stdc++.h>
    using namespace std; 
    int const N=1e5+10;  
    struct edge{
        int to,nt;  
    }e[N<<1];  
    int h[N],cnt,v[N],top[N],son[N],sz[N],n,q,sum,id[N],f[N][17],tin[N],tout[N],tot,d[40],s[N],dep[N]; 
    void add(int a,int b){
        e[++cnt].to=b; e[cnt].nt=h[a];  h[a]=cnt;  
    }
    inline int lowbit(int x){return x&-x;}
    int ins(int x){
        for(int i=30;i>=0;i--)  
            if(x&(1<<i)){
                if(d[i]) x^=d[i]; 
                else {
                    d[i]=x; 
                    return 1; 
                }
            }
        return 0; 
    }
    void dfs(int x,int fa,int d){
        sz[x]=1;  
        f[x][0]=fa;  
        tin[x]=++tot;  
        dep[x]=d; 
        for(int i=h[x];i;i=e[i].nt){
            int v=e[i].to; 
            if(v==fa) continue; 
            dfs(v,x,d+1);  
            sz[x]+=sz[v];  
            if(sz[son[x]]<sz[v])  
                son[x]=v;  
        }
        tout[x]=++tot;  
    }
    void dfs2(int x,int tp,int fa){
        top[x]=tp; 
        id[x]=++sum;  
        if(son[x]) dfs2(son[x],tp,x);  
        for(int i=h[x];i;i=e[i].nt){
            int v=e[i].to; 
            if(v==fa || v==son[x]) continue;  
            dfs2(v,v,x);  
        }
    }
    int ancestor(int x,int y){
        return tin[x]<=tin[y] && tout[y]<=tout[x];  
    }
    int lca(int x,int y){
        if(ancestor(x,y)) return x; 
        if(ancestor(y,x)) return y;  
        for(int i=16;i>=0;i--)  
            if(!ancestor(f[x][i],y)) x=f[x][i];  
        return f[x][0];  
    }
    void modify(int x,int v){
        for(int i=x;i<=n;i+=lowbit(i))
            s[i]^=v;  
    }
    void update(int x,int y,int z){
        while (top[x]^top[y]){
            int tx=top[x],ty=top[y];  
            if(dep[tx]<dep[ty]) 
                swap(x,y),swap(tx,ty);  
            modify(id[tx],z); 
            modify(id[x]+1,z);   
            x=f[tx][0];   
        }
        if(dep[x]<dep[y]) swap(x,y);  
        modify(id[y],z);  
        modify(id[x]+1,z); 
    }
    int getsum(int x){
        int res=0;  
        for(int i=x;i;i-=lowbit(i)) 
            res^=s[i];  
        return res;  
    }
    int main(){
        scanf("%d%d",&n,&q);  
        for(int i=1;i<=n;i++)  
            scanf("%d",&v[i]);  
        for(int i=1;i<n;i++){
            int x,y;  
            scanf("%d%d",&x,&y);
            add(x,y); 
            add(y,x); 
        }
        dfs(1,1,1);  
        dfs2(1,1,1);
        for(int j=1;j<=16;j++) 
            for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; 
        while (q--){
            char str[10]; 
            int x,y,z;  
            scanf("%s",str);  
            if(str[0]=='Q') {
                scanf("%d%d",&x,&y);  
                int t=lca(x,y);
                int dist=dep[x]+dep[y]-2*dep[t]+1;  
                if(dist>31) puts("YES"); 
                else{
                    memset(d,0,sizeof(d));  
                    int k=x,check=0; 
                    while (1){
                        int tmp=getsum(id[k]);  
                        if(!ins(tmp^v[k])) check=1;  
                        if(k==t) break;  
                        k=f[k][0];  
                    }
                    k=y;  
                    while (k!=t){
                        int tmp=getsum(id[k]);  
                        if(!ins(tmp^v[k])) check=1;  
                        k=f[k][0];  
                    }
                    puts(check?"YES":"NO");  
                }  
            }else {
                scanf("%d%d%d",&x,&y,&z);  
                update(x,y,z); 
            }
        }
        return 0; 
    }
    
posted @ 2020-06-14 00:32  zjxxcn  阅读(137)  评论(0编辑  收藏  举报