• HDU 3911 Black And White(线段树区间合并+lazy操作)


    开始以为是水题,结果。。。。。。 
    给你一些只有两种颜色的石头,0为白色,1为黑色。 
    然后两个操作: 
    1 l r 将[ l , r ]内的颜色取反 
    0 l r 计算[ l , r ]内最长连续黑色石头的个数

      明显的线段树区间合并,记录lmax(从左端点开始的最长值) rmax(从右端点开始的最长值) 用于更新mmax(区间最长值) 
      但是这儿有区间更新,所以记录0的三个最长值和1的三个最长值,更新父节点的时候交换0与1就好。 
      还有这儿注意查询时,可能值在查询的几个子区间的的相邻处(因为我们只能查询子区间内的最大值,而答案却是几个子区间合在一起的其中某一段)。我们可以根据代码看出,区间查询时一定是从左端点依次不重不漏的进入几个子区间到右端点,所以我们计算最大值时就使用左边的rmax加上右边的lmax。具体看代码

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    typedef unsigned long long ull;
    const int Inf=1<<28;
    const double Pi=acos(-1.0);
    const int Max=100010<<2;
    struct node
    {
        int llmax,lrmax,lmmax;
        int olmax,ormax,ommax;//最长的0个数 用于区间更新
    }segtr[Max];
    int upn[Max],tem;
    int nmax(int a,int b)
    {
        return a>b?a:b;
    }
    void Upnow(int now,int next,int sum)//区间更新
    {
        segtr[now].lmmax=nmax(nmax(segtr[next].lmmax,segtr[next|1].lmmax),segtr[next].lrmax+segtr[next|1].llmax);
    
        segtr[now].llmax=segtr[next].llmax;
        if(segtr[next].llmax==sum-(sum>>1))
            segtr[now].llmax+=segtr[next|1].llmax;
    
            segtr[now].lrmax=segtr[next|1].lrmax;
        if(segtr[next|1].lrmax==(sum>>1))
            segtr[now].lrmax+=segtr[next].lrmax;
    
             segtr[now].ommax=nmax(nmax(segtr[next].ommax,segtr[next|1].ommax),segtr[next].ormax+segtr[next|1].olmax);
    
        segtr[now].olmax=segtr[next].olmax;
        if(segtr[next].olmax==sum-(sum>>1))
            segtr[now].olmax+=segtr[next|1].olmax;
    
            segtr[now].ormax=segtr[next|1].ormax;
        if(segtr[next|1].ormax==(sum>>1))
            segtr[now].ormax+=segtr[next].ormax;
        return;
    }
    void Create(int sta,int enn,int now)
    {
        upn[now]=0;
        if(sta==enn)
        {
            scanf("%d",&tem);
            if(tem)//开始tem为1
            {
                segtr[now].ommax=segtr[now].olmax=segtr[now].ormax=0;
                segtr[now].lmmax=segtr[now].llmax=segtr[now].lrmax=1;
            }
            else
            {
                segtr[now].ommax=segtr[now].olmax=segtr[now].ormax=1;
                segtr[now].lmmax=segtr[now].llmax=segtr[now].lrmax=0;
            }
            return;
        }
        int mid=dir(sta+enn,1);
        int next=mul(now,1);
        Create(sta,mid,next);
        Create(mid+1,enn,next|1);
        Upnow(now,next,enn-sta+1);
        return;
    }
    void Swap(int &a,int &b)
    {
        int t=a;
        a=b;
        b=t;
        return;
    }
    void Cha(int now)//交换此段0与1的个数
    {
        Swap(segtr[now].lmmax,segtr[now].ommax);
        Swap(segtr[now].llmax,segtr[now].olmax);
        Swap(segtr[now].lrmax,segtr[now].ormax);
        return;
    }
    void Downow(int now)
    {
        if(upn[now])
        {
            int next=mul(now,1);
            upn[next]=(1+upn[next])%2;
            upn[next|1]=(1+upn[next|1])%2;
            Cha(next);
            Cha(next|1);
            upn[now]=0;
        }
        return;
    }
    int ans,mmid;//最终结果 没有断开就继续加
    void Update(int sta,int enn,int now,int x,int y,int z)//注意计算结果时虽然有回溯过程,但是一定是从**满足条件的最左边运行到最右边结束**
    {
        if(sta>=x&&enn<=y)
        {
            if(z)
            {
                upn[now]=(upn[now]+1)%2;
                Cha(now);
            }
            else//**关键是两边区间有连接的情况**
            {
                        mmid+=segtr[now].llmax;
                    ans=nmax(nmax(ans,mmid),segtr[now].lmmax);
                    if(segtr[now].llmax==enn-sta+1);//整个区间相连
                   else
                    mmid=segtr[now].lrmax;
            }
            return;
        }
        Downow(now);
        int mid=dir(sta+enn,1);
        int next=mul(now,1);
        if(mid>=x)
          Update(sta,mid,next,x,y,z);
        if(mid<y)
             Update(mid+1,enn,next|1,x,y,z);
            Upnow(now,next,enn-sta+1);
        return;
    }
    int main()
    {
        int n,m;
        int p,lef,rig;
        while(~scanf("%d",&n))
        {
            Create(1,n,1);
            scanf("%d",&m);
            while(m--)
            {
                scanf("%d %d %d",&p,&lef,&rig);
                if(!p)
                {
                    mmid=ans=0;
                    Update(1,n,1,lef,rig,0);
                    printf("%d
    ",ans);
                }
                else
                Update(1,n,1,lef,rig,1);
            }
        }
        return 0;
    }
  • 相关阅读:
    System.Environment.GetFolderPath函数中未开放的枚举参数
    如何获得TextBox里光标位置
    c#中用windows api函数修改内存数据
    C#客户端绑定DataView和DataTable的几个技巧
    如何锁定windows系统以及调用其它系统对话框
    c#中拖动图片的例子
    php数据库操作类mysql
    二级下拉关联菜单 js
    服务器端用 mysql_real_escape_string 清洁客户端数据
    心电正常值范围
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5863691.html
Copyright © 2020-2023  润新知