hdu 3911 Black And White(线段树的延迟标记法)

题意:就是给你一段由0和1组成的序列,然后有两种操作:0 a b就是问从a到b最长的连续的1的长度为多少,1 a b就是把从a到b的数据是一的更新为0,是零的更新为1.

思路:用一个结构体,lone表示从最左边数连续1的长度,lzero表示从左边数连续0的长度,rone表示从右边数连续1的长度,rzero表示从右边数连续0的长度,tmax0表示连续最长的0的个数,tmax1表示连续最长的1的个数,flag用来做延迟标记,具体的东西见代码。

代码实现:

#include<iostream>
using namespace std;
struct node{
   int lone,lzero;
   int rone,rzero;
   int tmax0,tmax1;
   int flag;//延迟标记,这里要注意下,开始的时候我就是一直错的
   int l,r;
   int mlen;//节点的区间长度
}p[100001*4];
int a[100001];
int max(int x,int y)
{
    return x>y?x:y;
}
int min(int x,int y)
{
    return x<y?x:y;
}
void update_info(int n)//向上更新
{
    p[n].lone=p[n*2].lone;
    if(p[n*2].lone==p[n*2].mlen)//可以合并
        p[n].lone+=p[n*2+1].lone;
    p[n].lzero=p[n*2].lzero;
    if(p[n*2].lzero==p[n*2].mlen)//可以合并
        p[n].lzero+=p[n*2+1].lzero;
    p[n].rone=p[n*2+1].rone;
    if(p[n*2+1].rone==p[n*2+1].mlen)//可以合并
        p[n].rone+=p[n*2].rone;
    p[n].rzero=p[n*2+1].rzero;
    if(p[n*2+1].rzero==p[n*2+1].mlen)//可以合并
        p[n].rzero+=p[n*2].rzero;
    p[n].tmax0=max(p[n*2].tmax0,p[n*2+1].tmax0);//取左右子树的大者
    p[n].tmax0=max(p[n].tmax0,p[n*2].rzero+p[n*2+1].lzero);//和合并之后的比较
    p[n].tmax1=max(p[n*2].tmax1,p[n*2+1].tmax1);//同理
    p[n].tmax1=max(p[n].tmax1,p[n*2].rone+p[n*2+1].lone);
}
void build(int l,int r,int n)//建树的过程
{
    p[n].l=l;
    p[n].r=r;
    p[n].flag=0;
    p[n].mlen=(r-l+1);
    if(l==r)
    {
        if(a[l]==1)
        {
            p[n].lone=1;
            p[n].lzero=0;
            p[n].rone=1;
            p[n].rzero=0;
            p[n].tmax0=0;
            p[n].tmax1=1;
        }
        else
        {
            p[n].lone=0;
            p[n].lzero=1;
            p[n].rone=0;
            p[n].rzero=1;
            p[n].tmax0=1;
            p[n].tmax1=0;
        }
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,n*2);
    build(mid+1,r,n*2+1);
    update_info(n);//往上更新
}
void pushdown(int n)//往下更新
{
   p[n*2].flag=p[n*2].flag^1;//这里是异或操作注意一下哦
   p[n*2+1].flag=p[n*2+1].flag^1;//这里是异或操作注意一下哦
   swap(p[n*2].lone,p[n*2].lzero);
   swap(p[n*2].rone,p[n*2].rzero);
   swap(p[n*2].tmax1,p[n*2].tmax0);

   swap(p[n*2+1].lone,p[n*2+1].lzero);
   swap(p[n*2+1].rone,p[n*2+1].rzero);
   swap(p[n*2+1].tmax1,p[n*2+1].tmax0);
   p[n].flag=0;
}
void insert(int x,int y,int n)
{
    if(x==p[n].l&&y==p[n].r)
    {
        swap(p[n].lone,p[n].lzero);
        swap(p[n].rzero,p[n].rone);
        swap(p[n].tmax1,p[n].tmax0);
        p[n].flag=p[n].flag^1;//这里是异或操作注意一下哦
        return ;
    }
    if(p[n].flag==1)
        pushdown(n);//往下更新
    int mid=(p[n].l+p[n].r)/2;
    if(y<=mid)
        insert(x,y,n*2);
    else if(x>mid)
        insert(x,y,n*2+1);
    else
    {
        insert(x,mid,n*2);
        insert(mid+1,y,n*2+1);
    }
    update_info(n);//往上更新
}
int sum(int x,int y,int n)//求连续1的最长的长度
{
    if(x==p[n].l&&y==p[n].r)
       return p[n].tmax1;
    int mid=(p[n].l+p[n].r)/2;
    if(p[n].flag==1)
        pushdown(n);//往下更新
    if(y<=mid)
        return sum(x,y,n*2);
    else if(x>mid)
        return sum(x,y,n*2+1);
    else
    {
        int left=0,right=0,midden=0;
        midden=min(mid-x+1,p[n*2].rone)+min(y-mid,p[n*2+1].lone);
        left=sum(x,mid,n*2);
        right=sum(mid+1,y,n*2+1);
        return max(midden,max(left,right));
    }
}
int main()
{
    int n,m,i,nima,x,y;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&nima,&x,&y);
            if(nima==1)
                insert(x,y,1);
            else
                printf("%d\n",sum(x,y,1));
        }
    }
    return 0;
}

还有一道同类型的题目,可以去做下,链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397这道要难些 这是我的博客链接:http://www.cnblogs.com/jiangjing/archive/2013/01/18/2866206.html

posted on 2013-01-16 19:35  后端bug开发工程师  阅读(1119)  评论(0编辑  收藏  举报

导航