暑假集训每日一题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;
}
原文地址:https://www.cnblogs.com/algorithms/p/2587801.html