zoukankan      html  css  js  c++  java
  • 暑假集训每日一题0712 (线段树)

    维护一个只有0和1的整数序列,支持以下操作:
    1 x y v : 将区间[x,y]之间的所有整数都变为v(v为0或1);
    2 x y : 将区间[x,y]之间所有的1变为0,所有的0变为1;
    3 x y : 查询区间[x,y]内的1的个数。

    线段数练习:每段保存3个关键信息:和,修改标记,反转标记。

    需注意的几点:

    在更新某段时,之前的反转操作将无效,应将其清零,在下传修改标记时,应将左右儿子的反转标记清零。

    View Code
    #include <stdio.h>
    #define N 100001
    int n,m,ans;
    int a[N],sum[4*N],val[4*N],rev[4*N];
    void update(int cur)
    {
        int ls=cur<<1,rs=cur<<1|1;
        sum[cur]=sum[ls]+sum[rs];
    }
    void pushdown(int cur,int x,int y)
    {
        int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
        if(x==y)    return;
        if(val[cur]!=-1)
        {
            val[ls]=val[rs]=val[cur];
            sum[ls]=val[cur]*(mid-x+1);
            sum[rs]=val[cur]*(y-mid);
            val[cur]=-1;
            rev[ls]=rev[rs]=0;
        }
        if(rev[cur])
        {
            rev[ls]^=1;
            rev[rs]^=1;
            sum[ls]=mid-x+1-sum[ls];
            sum[rs]=y-mid-sum[rs];
            rev[cur]=0;
        }
    }
    void build(int cur,int x,int y)
    {
        int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
        val[cur]=-1;
        rev[cur]=0;
        if(x==y)
        {
            sum[cur]=a[x];
            return;
        }
        build(ls,x,mid);
        build(rs,mid+1,y);
        update(cur);
    }
    void change(int cur,int x,int y,int s,int t,int value)
    {
        int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
        if(x>=s && y<=t)
        {
            sum[cur]=(y-x+1)*value;
            val[cur]=value;
            rev[cur]=0;
            return;
        }
        pushdown(cur,x,y);
        if(mid>=s)  change(ls,x,mid,s,t,value);
        if(mid+1<=t)    change(rs,mid+1,y,s,t,value);
        update(cur);
    }
    void reverse(int cur,int x,int y,int s,int t)
    {
        int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
        if(x>=s && y<=t)
        {
            sum[cur]=y-x+1-sum[cur];
            rev[cur]^=1;
            return;
        }
        pushdown(cur,x,y);
        if(mid>=s)  reverse(ls,x,mid,s,t);
        if(mid+1<=t)    reverse(rs,mid+1,y,s,t);
        update(cur);
    }
    void query(int cur,int x,int y,int s,int t)
    {
        int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
        if(x>=s && y<=t)
        {
            ans+=sum[cur];
            return;
        }
        pushdown(cur,x,y);
        if(mid>=s)  query(ls,x,mid,s,t);
        if(mid+1<=t)    query(rs,mid+1,y,s,t);
    }
    int main()
    {
        int i,opt,x,y,z;
        while(~scanf("%d",&n))
        {
            for(i=1;i<=n;i++)   scanf("%d",&a[i]);
            build(1,1,n);
            scanf("%d",&m);
            while(m--)
            {
                scanf("%d%d%d",&opt,&x,&y);
                if(opt==3)
                {
                    ans=0;
                    query(1,1,n,x,y);
                    printf("%d\n",ans);
                }
                else if(opt==2) reverse(1,1,n,x,y);
                else
                {
                    scanf("%d",&z);
                    change(1,1,n,x,y,z);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    透视投影矩阵的推导
    选择排序
    递归运动函数的实现
    插入排序
    基本光照模型
    顶点法向量从物体坐标系变换到世界坐标系
    Phong和BlinnPhong光照模型
    unity3d使用脚本保存屏幕截图
    【转】C++11常用特性的使用经验总结
    右手坐标系下LookAt视图矩阵的推导
  • 原文地址:https://www.cnblogs.com/algorithms/p/2587801.html
Copyright © 2011-2022 走看看