zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    jQuery 复选框全选反选
    JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的 开源 Java EE快速开发平台
    SpringMVC+MyBatis(最新)
    基于Maven构建整合SpringMVC+Mybtis+Druid
    alibaba的FastJson(高性能JSON开发包)
    JAVA中使用JSON进行数据传递
    java 发送http json请求
    JDK中的URLConnection参数详解
    java调用Http请求 -HttpURLConnection学习
    Jquery调用webService的四种方法
  • 原文地址:https://www.cnblogs.com/jiangjing/p/2863266.html
Copyright © 2011-2022 走看看