• 【转】poj 1823 hotel 线段树【Good】


    题意:一个hotel,有n个连续的房间,开始时均无人住宿

    共有3种操作

    1 a b 从a开始连续b个房间全部旅客住宿 [a,a+b-1];

    2 a b 从a开始连续b个房间全部旅客离开 [a,a+b-1];

    3 查询最长连续空房间

    思路:线段树,记录每个节点,左边,右边各最多连续空房间lmax,rmax; 以及这个区间内最多空房间max

    #include<iostream>
     #include<cmath>
     using namespace std;
     #define MAXN 16001
     struct node
     {
         int lmax,rmax,max;
         int left,right;
         int flag;//0:全空;1:全部被占用;2:部分被占用
     };
     node tree[MAXN*4];
     void build(int i)
     {
         tree[i].lmax=tree[i].rmax=tree[i].max=tree[i].right-tree[i].left+1;//当前节点的max,lmax和rmax都初始化为right-left+1
         tree[i].flag=0;
         if(tree[i].left==tree[i].right) return ;
         int mid=(tree[i].left+tree[i].right)/2;
         tree[2*i].left=tree[i].left; tree[2*i].right=mid;
         tree[2*i+1].left=mid+1; tree[2*i+1].right=tree[i].right;
         build(2*i); build(2*i+1);
     }
     
     void insert(int i,int x,int y,int c)
     {
         //cout<<i<<" "<<x<<" "<<y<<" "<<c<<" "<<tree[i].left<<" "<<tree[i].right<<endl;
         if(tree[i].left==x&&tree[i].right==y)
         {
             tree[i].flag=c;
             if(c==1) tree[i].lmax=tree[i].rmax=tree[i].max=0;
             else tree[i].lmax=tree[i].rmax=tree[i].max=tree[i].right-tree[i].left+1;
             return;
         }

       //当前节点完全递归返回前未被占用,保证“当前节点的子节点的状态被标记为0”优先级最高

       //具体解析:因为之前操作中的插入或者删除操作都是到达满足if(tree[i].left==x&&tree[i].right==y)的条件之后就返回了,

       //但是我们之后要进行的插入和删除操作要是区段有可能比之前涉及到的区段小,这个时候在递归之前判断当前节点状态并且

       //对相应左子树和右子树执行更新操作就很有必要了
         if(tree[i].flag==0)
         {
             tree[2*i].flag=tree[2*i+1].flag=0;

       //左右子树的各个最长子段都设为right-left+1
             tree[2*i].lmax=tree[2*i].rmax=tree[2*i].max=tree[2*i].right-tree[2*i].left+1;
             tree[2*i+1].lmax=tree[2*i+1].rmax=tree[2*i+1].max=tree[2*i+1].right-tree[2*i+1].left+1;
         }

       //当前节点递归返回前完全被占用,保证“当前节点的子节点的状态被标记为1”优先级最高(具体解析同上)
         if(tree[i].flag==1)
         {  
             tree[2*i].flag=tree[2*i+1].flag=1;
       //左右子树的各个最长子段都设为0
             tree[2*i].lmax=tree[2*i].rmax=tree[2*i].max=0;
             tree[2*i+1].lmax=tree[2*i+1].rmax=tree[2*i+1].max=0;
         }
      //递归操作
         int mid=(tree[i].left+tree[i].right)/2;
         if(y<=mid) insert(2*i,x,y,c);
         else if(x>mid) insert(2*i+1,x,y,c);
         else
         {
             insert(2*i,x,mid,c);
             insert(2*i+1,mid+1,y,c);
         }
      //延迟处理,更新当前节点的状态
         if(tree[2*i].flag==0&&tree[2*i+1].flag==0)//左右子树均全空
         {
             tree[i].flag=0;
             tree[i].lmax=tree[i].rmax=tree[i].max=tree[i].right-tree[i].left+1;
         }
         else if(tree[2*i].flag==0&&tree[2*i+1].flag==1)//左子树全空,右子树全被占用
         {
             tree[i].flag=2;
             tree[i].lmax=tree[i].max=tree[2*i].max;
             tree[i].rmax=0;
         }
         else if(tree[2*i].flag==1&&tree[2*i+1].flag==0)//左子树被占用,右子树全空
         {
             tree[i].flag=2;
             tree[i].rmax=tree[i].max=tree[2*i+1].max;
             tree[i].lmax=0;
         }
         else if(tree[2*i].flag==1&&tree[2*i+1].flag==1)//左右子树都全被占用
         {
             tree[i].flag=1;       
             tree[i].lmax=tree[i].rmax=tree[i].max=0;  
         }
         else//左子树或者右子树含有部分被占用的情况
         {
             tree[i].flag=2;
             tree[i].max=max(tree[2*i].max,tree[2*i+1].max);
             tree[i].max=max(tree[i].max,tree[2*i].rmax+tree[2*i+1].lmax);
             if(tree[2*i].flag==0)

                     tree[i].lmax=tree[2*i].max+tree[2*i+1].lmax;
             else

                      tree[i].lmax=tree[2*i].lmax;
             if(tree[2*i+1].flag==0)

          tree[i].rmax=tree[2*i].rmax+tree[2*i+1].max;
             else

                     tree[i].rmax=tree[2*i+1].rmax;
         }
     } 
     int main()
     {
         int n,m;
         scanf("%d%d",&n,&m);
         tree[1].left=1; tree[1].right=n;
         build(1);
         int i;
         int x,y,c;
         for(i=1;i<=m;i++)
         {
             scanf("%d",&c);
             if(c==3) printf("%d\n",tree[1].max);
             if(c==1)
             {
                 scanf("%d%d",&x,&y);
                 insert(1,x,x+y-1,1);
             }
             if(c==2)
             {
                 scanf("%d%d",&x,&y);
                 insert(1,x,x+y-1,0);
             }
         }
         return 0;
     }

  • 相关阅读:
    遮罩层代码
    get方法传递中文数据的时候如何进行转码
    Eclipse常用快捷键
    VS常用快捷键
    Java笔记10-Object包装类型字符串
    MySQL常用命令
    Oracle笔记3-高级查询
    Oracle笔记2-数据库设计
    Java笔记9-正则表达式
    Java笔记8-抽象接口
  • 原文地址:https://www.cnblogs.com/lzhitian/p/2612647.html
Copyright © 2020-2023  润新知