暑假集训每日一题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;

}

你可能感兴趣的:(线段树)