• CF877E


    Description

    给定一棵权值只能为 (1)(0) 的树,对其进行两种操作。

    一种是将其中的某棵子树取反,另一种是询问某棵子树中 (1) 的个数。

    Solution

    比较板的线段树。

    显然的,假设一棵大小为 (x) 的子树中有 (y) 个 1,那么这棵子树取反后就有 (x-y)(1)

    题目只需要我们维护一种信息,然后这种信息的变换只有这一种方法,所以我们知道了这个性质就可以直接搞了。

    根据区间修改维护懒标记的原理,当一个点的子树取反后,它的左右儿子都要取反,因此懒标记下传时也不断取反就可以了。

    然后就做完了。

    Code

    #include<bits/stdc++.h>
    #define maxn 2001000
    #define INF 0x3f3f3f3f 
    //#define int long long
    
    using namespace std;
    
    int n,m,tot,cnt;
    int a[maxn],head[maxn],lazy[maxn];
    int sum[maxn],val[maxn],fa[maxn];
    int dfn[maxn],top[maxn],son[maxn];
    int dep[maxn],siz[maxn],pre[maxn];
    struct edge{int fr,to,nxt;}e[maxn];
    
    int read(){
    	int s=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
    	return s*w;
    }
    
    void add(int fr,int to){
        e[++tot].fr=fr;e[tot].to=to;
        e[tot].nxt=head[fr];head[fr]=tot;
    }
    
    namespace Seg{
        #define ls x<<1
        #define rs x<<1|1
        void pushup(int x){
            sum[x]=sum[ls]+sum[rs];
        }
        
        void pushdown(int x,int ln,int rn){
            if(!lazy[x]) return;
            lazy[ls]^=1;
            lazy[rs]^=1;
            sum[ls]=ln-sum[ls];
            sum[rs]=rn-sum[rs];
            lazy[x]=0;
        }
        
        void build(int x,int l,int r){
            if(l==r){sum[x]=a[pre[l]];return;} 
            int mid=l+r>>1;
            build(ls,l,mid);build(rs,mid+1,r);
            pushup(x);
        }
        
        void update(int x,int l,int r,int L,int R){
            if(L<=l&&R>=r){sum[x]=r-l+1-sum[x],lazy[x]^=1;return;}
            int mid=l+r>>1;pushdown(x,mid-l+1,r-mid);
            if(L<=mid) update(ls,l,mid,L,R);
            if(R>=mid+1) update(rs,mid+1,r,L,R);
            pushup(x); 
        }
        
        int query(int x,int l,int r,int L,int R){
            if(L<=l&&R>=r)return sum[x];
            int mid=l+r>>1,ans=0;pushdown(x,mid-l+1,r-mid);
            if(L<=mid) ans+=query(ls,l,mid,L,R);
            if(R>=mid+1) ans+=query(rs,mid+1,r,L,R);
            return ans;
        }
    }
    
    namespace Cut{
        void dfs1(int x,int fat){
            dep[x]=dep[fat]+1;
            fa[x]=fat;siz[x]=1;
            for(int i=head[x];i;i=e[i].nxt){
                int to=e[i].to;
                if(to==fat) continue;
                dfs1(to,x);siz[x]+=siz[to];
                if(siz[to]>siz[son[x]])son[x]=to;
            }
        }
        
        void dfs2(int x,int tp){
            top[x]=tp;dfn[x]=++cnt;pre[cnt]=x;
            if(son[x]) dfs2(son[x],tp);
            for(int i=head[x];i;i=e[i].nxt){
                int to=e[i].to;
                if(to==fa[x]||to==son[x]) continue;
                dfs2(to,to);
            }
        }
    }
    
    int main(){
        n=read();
        for(int i=2,fa;i<=n;i++) fa=read(),add(fa,i);
        for(int i=1;i<=n;i++) a[i]=read();m=read();
        Cut::dfs1(1,0);Cut::dfs2(1,1);Seg::build(1,1,n);
        for(int i=1,pos;i<=m;i++){
            string opt;cin>>opt;pos=read();
            if(opt[0]=='g') printf("%d
    ",Seg::query(1,1,n,dfn[pos],dfn[pos]+siz[pos]-1));
            else if(opt[0]=='p') Seg::update(1,1,n,dfn[pos],dfn[pos]+siz[pos]-1);
        }
        return 0;
    }
    
  • 相关阅读:
    Python数组/切片
    ArcGISEngine 版本升级的方法
    c# 使用类名称访问成员变量
    向模拟器里添加图片的简单方法
    通过self调用propery和直接调用propery的区别
    Objectivec 使用构造函数来初始化函数并调用函数的方法
    IPhone模拟器截取当前活动窗体,并保存为图片
    Windows Server2008 安装Oracle失败
    ALL、DISTINCT、DISTINCTROW、TOP 谓词
    ObjectiveC 语法快速参考
  • 原文地址:https://www.cnblogs.com/KnightL/p/14700943.html
Copyright © 2020-2023  润新知