HDU3911 Black And White(黑白子)

题意:给一行棋子(只有黑色和白色,1为黑,0为白),长度为100000。有m个操作,x,l,r  若x==0,查询(l,r)区间内连续的黑棋最大数量,若x==1,翻转(l,r)区间。

#include <iostream>
#include<stdio.h>
using namespace std;
#define maxn 500001
int n,m,a[maxn];
int max(int x,int y,int z)
{
 return max(max(x,y),z);
}
void swap(int *ji1,int *ji2)
{
    int t;
    t=*ji1;
    *ji1=*ji2;
    *ji2=t;
}
struct node
{
    int l,r,ll1,rr1,m1,ll0,rr0,m0,c;
}tr[maxn*4];
void pushup(int id)
{
    int len1,len2;
    len1=tr[id*2].r-tr[id*2].l+1;
    len2=tr[id*2+1].r-tr[id*2+1].l+1;

    tr[id].ll1=tr[id*2].ll1;
    tr[id].rr1=tr[id*2+1].rr1;
    if(tr[id*2].ll1==len1)tr[id].ll1+=tr[id*2+1].ll1;
    if(tr[id*2+1].rr1==len2)tr[id].rr1+=tr[id*2].rr1;
    tr[id].m1=max(tr[id*2].m1,tr[id*2+1].m1,tr[id*2].rr1+tr[id*2+1].ll1);//在id节点 只考虑ll1,rr1但是有可能中间段是最大的

    tr[id].ll0=tr[id*2].ll0;
    tr[id].rr0=tr[id*2+1].rr0;
    if(tr[id*2].ll0==len1)tr[id].ll0+=tr[id*2+1].ll0;
    if(tr[id*2+1].rr0==len2)tr[id].rr0+=tr[id*2].rr0;
    tr[id].m0=max(tr[id*2].m0,tr[id*2+1].m0,tr[id*2].rr0+tr[id*2+1].ll0);

}
void bulid(int id,int l,int r)
{
    tr[id].l=l;
    tr[id].r=r;
    tr[id].c=0;
    if(l==r)
    {
        tr[id].ll1=tr[id].m1=tr[id].rr1=a[l]?1:0;
        tr[id].ll0=tr[id].m0=tr[id].rr0=a[l]?0:1;
    }
    else
    {
        int mid=(l+r)/2;
        bulid(id*2,l,mid);
        bulid(id*2+1,mid+1,r);
        pushup(id);
    }
}
void exchang(int id)
{
    if(tr[id].c==1)
    tr[id].c=0;
    else tr[id].c=1;//此处注意,重复更新同样的区间,则相当于没更新
    swap(tr[id].ll0,tr[id].ll1);
    swap(tr[id].rr0,tr[id].rr1);
    swap(tr[id].m0,tr[id].m1);
}
void pushdown(int id)
{
    exchang(id*2);
    exchang(id*2+1);
    tr[id].c=0;
}
int query(int id,int l,int r)
{
    if(l<=tr[id].l&&tr[id].r<=r)
    {
        return tr[id].m1;
    }
    else
    {
        if(tr[id].c!=0)
        {
            pushdown(id);
        }
        int mid=(tr[id].r+tr[id].l)/2;
        if(r<=mid)return query(id*2,l,r);
        else if(l>mid)return query(id*2+1,l,r);
        //*************************//
        else
        {
            int l1=query(id*2,l,r);
            int r1=query(id*2+1,l,r);
            int a=tr[id*2].rr1;//左子树右边最长连续1,注意它的个数不应该大于区间[l,tr[rt<<1].r]的个数
            int b=tr[id*2+1].ll1;//右子树左边最长连续1,注意它的个数不应该大于区间[tr[rt<<1|1].l,r]的个数
            if(a>tr[id*2].r-l+1)a=tr[id*2].r-l+1;
            if(b>r-tr[id*2+1].l+1)b=r-tr[id*2+1].l+1;
            return  max(l1,r1,a+b);

        }
        //*************************//
    }
}
void update(int id,int l,int r)
{
    if(l<=tr[id].l&&tr[id].r<=r)
    {
       exchang(id);//此处注意,重复更新同样的区间,则相当于没更新
    }
    else
    {
        if(tr[id].c!=0)
        pushdown(id);
        int mid=(tr[id].r+tr[id].l)/2;
        if(r<=mid)update(id*2,l,r);
        else if(l>mid)update(id*2+1,l,r);
        else
        {
            update(id*2,l,r);
            update(id*2+1,l,r);
        }
        pushup(id);
    }
}
int main()
{
    int i,l,r,t;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        bulid(1,1,n);

         scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&t,&l,&r);
            if(t==0)
            {
                printf("%d\n",query(1,l,r));
            }
            else
            {
                update(1,l,r);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值