西安邀请赛-E(树链剖分+线段树)

题目链接:https://nanti.jisuanke.com/t/39272

题意:给一棵树,n个结点,树根为1,n-1条边,每个结点有一个权值。进行3种操作:

    1 s t:把1和s之间的最短路径上的所有结点|t。

    2 s t:把1和s之间的最短路径上的所有结点&t。

    3 s t:把1和s之间的最短路径上的所有结点进行异或,若结果等于t则输出NO,否则输出YES。(不理解的话可以看一下nim博弈论)

思路:很明显的一道题树链剖分题,难的是怎么维护线段树。我们拆成二进制来看,用num[32]维护区间内所有点对应位的1的数量,对于或操作来说,若对应位为1,则区间所有点对应位全改为1,若为0,则不操作; 对于与操作来说,若对应位为0,则区间所有点对应位全为0,若为1,则不操作。而且这两种操作是具有覆盖效果的,那么我们可以用懒惰标记add[i]=1表示该区间第i位全为1,add[i]=-1表示该区间第i位全为0。查询操作时,将查询区间上所有位1的数量模2,即区间异或和的对应位,将其与输入的t比较是否相等即可。

AC代码:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=100005;

int cnt1,head[maxn];
int dep[maxn],siz[maxn],fa[maxn],son[maxn],top[maxn],cnt2,id[maxn],w[maxn],wt[maxn],res;
int n,m;

struct node1{
    int v,nex;
}edge[maxn<<1];

void adde(int u,int v){
    edge[++cnt1].v=v;
    edge[cnt1].nex=head[u];
    head[u]=cnt1;
}

struct node2{
    int l,r,len;
    int num[32],add[32];
}tr[maxn<<2];

void pushup(int v){
    for(int i=0;i<30;++i)
        tr[v].num[i]=tr[v<<1].num[i]+tr[v<<1|1].num[i];
}

void pushdown(int v){
    for(int i=0;i<30;++i){
        if(tr[v].add[i]==1){
            tr[v<<1].num[i]=tr[v<<1].len;
            tr[v<<1].add[i]=1;
            tr[v<<1|1].num[i]=tr[v<<1|1].len;
            tr[v<<1|1].add[i]=1;
            tr[v].add[i]=0;
        }
        if(tr[v].add[i]==-1){
            tr[v<<1].num[i]=0;
            tr[v<<1].add[i]=-1;
            tr[v<<1|1].num[i]=0;
            tr[v<<1|1].add[i]=-1;
            tr[v].add[i]=0;
        }
    }
}

void build(int v,int l,int r){
    tr[v].l=l,tr[v].r=r,tr[v].len=r-l+1;
    if(l==r){
        for(int i=0;i<30;++i)
            if((1<<i)&wt[r])
                tr[v].num[i]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(v<<1,l,mid);
    build(v<<1|1,mid+1,r);
    pushup(v);
}

void update(int v,int l,int r,int op,int k){
    if(l<=tr[v].l&&r>=tr[v].r){
        if(op==1){
            for(int i=0;i<30;++i)
                if((1<<i)&k){
                    tr[v].num[i]=tr[v].len;
                    tr[v].add[i]=1;
                }
        }
        else{
            for(int i=0;i<30;++i)
                if(!((1<<i)&k)){
                    tr[v].num[i]=0;
                    tr[v].add[i]=-1;
                }
        }
        return;
    }
    pushdown(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(l<=mid) update(v<<1,l,r,op,k);
    if(r>mid) update(v<<1|1,l,r,op,k);
    pushup(v);
}

void query(int v,int l,int r){
    if(l<=tr[v].l&&r>=tr[v].r){
        for(int i=0;i<30;++i){
            if(tr[v].num[i]&1)
                res^=(1<<i);
        }
        return;
    }
    pushdown(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(l<=mid) query(v<<1,l,r);
    if(r>mid) query(v<<1|1,l,r);
}

void dfs1(int x,int f,int deep){
    fa[x]=f;
    dep[x]=deep;
    siz[x]=1;
    int maxson=-1;
    for(int i=head[x];i;i=edge[i].nex){
        int y=edge[i].v;
        if(y==f) continue;
        dfs1(y,x,deep+1);
        siz[x]+=siz[y];
        if(siz[y]>maxson) son[x]=y,maxson=siz[y];
    }
}

void dfs2(int x,int tp){
    id[x]=++cnt2;
    wt[cnt2]=w[x];
    top[x]=tp;
    if(!son[x]) return;
    dfs2(son[x],tp);
    for(int i=head[x];i;i=edge[i].nex){
        int y=edge[i].v;
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}

void updRange(int x,int y,int op,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,id[top[x]],id[x],op,k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    update(1,id[x],id[y],op,k);
}

void qRange(int x,int y){
    res=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        query(1,id[top[x]],id[x]);
        x=fa[top[x]];        
    }
    if(dep[x]>dep[y]) swap(x,y);
    query(1,id[x],id[y]);
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%d",&w[i]);
    for(int i=1;i<n;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        adde(x,y);
        adde(y,x);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    while(m--){
        int op,s,t;
        scanf("%d%d%d",&op,&s,&t);
        if(op==1||op==2)
            updRange(1,s,op,t);    
        else{
            qRange(1,s);
            if(res==t) printf("NO\n");
            else printf("YES\n");
        }
    }
    return 0;
}

 

 

 

 

posted @ 2019-07-14 10:48  Frank__Chen  阅读(170)  评论(0编辑  收藏  举报