zoukankan      html  css  js  c++  java
  • poj3667(bzoj1593)--Usaco08Feb Hotel--线段树区间合并

    Description

    奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光。作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿。这个巨大的旅馆一共有N (1 <= N <= 50,000)间客房,它们在同一层楼中顺次一字排开,在任何一个房间里,只需要拉开窗帘,就能见到波光粼粼的湖面。 贝茜一行,以及其他慕名而来的旅游者,都是一批批地来到旅馆的服务台,希望能订到Di (1 <= Di <= N)间连续的房间。服务台的接待工作也很简单:如果存在r满足编号为r..r+Di -1的房间均空着,他就将这一批顾客安排到这些房间入住;如果没有满足条件的r,他会道歉说没有足够的空房间,请顾客们另找一家宾馆。如果有多个满足条件的r,服务员会选择其中最小的一个。 旅馆中的退房服务也是批量进行的。每一个退房请求由2个数字Xi、Di 描述,表示编号为Xi..Xi+Di -1 (1 <= Xi <= N-Di +1)房间中的客人全部离开。退房前,请求退掉的房间中的一些,甚至是所有,可能本来就无人入住。 而你的工作,就是写一个程序,帮服务员为旅客安排房间。你的程序一共需要处理M (1 <= M < 50,000)个按输入次序到来的住店或退房的请求。第一个请求到来前,旅店中所有房间都是空闲的。

    Input

    * 第1行: 2个用空格隔开的整数:N、M

    * 第2..M+1行: 第i+1描述了第i个请求,如果它是一个订房请求,则用2个数字 1、Di描述,数字间用空格隔开;如果它是一个退房请求,用3 个以空格隔开的数字2、Xi、Di描述

    Output

    * 第1..??行: 对于每个订房请求,输出1个独占1行的数字:如果请求能被满足 ,输出满足条件的最小的r;如果请求无法被满足,输出0

    Sample Input

    10 6
    1 3
    1 3
    1 3
    1 3
    2 5 5
    1 6 

    Sample Output

    1
    4
    7
    0
    5
     
    题解:
      感觉思想上和小白逛公园有一点像。
      此问题抽象化为:
        1.对于一个序列,求是否有连续的一段长为Di的区间的值都为0。如果有,输出最小的左端点编号;如果没有,输出0;
        2.清空一段区间的值。
      这题维护的信息是:
        l_len----从区间左端点开始的最长0子串长度
        r_len----从区间右端点开始的最长0子串长度
        t_len----整个区间内最长0子串长度
        lzy----当前房间状态
      合并都写注释里了。
      1 #include<cmath>
      2 #include<algorithm>
      3 #include<cstdio>
      4 #include<iostream>
      5 #include<cstring>
      6 using namespace std;
      7 const int maxn=50009;
      8 
      9 struct tree
     10 {
     11     int lzy,l,r;
     12     int l_len,r_len,t_len;
     13     int get_len()
     14     {
     15         return r-l+1;
     16     }
     17     int get_mid()
     18     {
     19         return (l+r)>>1;
     20     }
     21     void new_len()
     22     {
     23         t_len=r_len=l_len=(lzy?0:get_len());
     24     }
     25 }tr[maxn<<2];
     26 int n,m,d[maxn];
     27 
     28 void build(int x,int la,int ra)
     29 {
     30     tr[x].l=la;tr[x].r=ra;
     31     tr[x].t_len=tr[x].r_len=tr[x].l_len=tr[x].get_len();
     32     tr[x].lzy=0;//初始时旅馆没有客人
     33     if(la==ra)return;
     34     int mid=tr[x].get_mid();
     35     build(x<<1,la,mid);
     36     build(x<<1|1,mid+1,ra);
     37     return;
     38 }
     39 
     40 int ask(int tot,int x)
     41 {
     42     if(tr[x].l==tr[x].r&&tot==1)
     43         return tr[x].l;//只需要一间的时候
     44     if(tr[x].lzy!=-1)
     45     {
     46         tr[x<<1].lzy=tr[x<<1|1].lzy=tr[x].lzy;
     47         tr[x].lzy=-1;
     48         tr[x<<1].new_len();tr[x<<1|1].new_len();
     49     }
     50     if(tr[x<<1].t_len>=tot)//在左区间找
     51         return ask(tot,x<<1);
     52     else if(tr[x<<1].r_len+tr[x<<1|1].l_len>=tot)//中间拼起来的区间刚好覆盖
     53         return tr[x<<1].r-tr[x<<1].r_len+1;//直接返回此区间的左端点
     54     else if(tr[x<<1|1].t_len>=tot)//在右区间里找
     55         return ask(tot,x<<1|1);
     56     else
     57         return 0;//没有空房间啦qwq
     58 }
     59 
     60 void update(int x,int w,int la,int ra)
     61 {
     62     if(tr[x].l==la&&ra==tr[x].r)
     63     {
     64         tr[x].lzy=w;
     65         tr[x].new_len();
     66         return;
     67     }
     68     if(tr[x].lzy!=-1)
     69     {//下传lazy标记
     70         tr[x<<1].lzy=tr[x<<1|1].lzy=tr[x].lzy;
     71         tr[x].lzy=-1;
     72         tr[x<<1].new_len();//更新覆盖情况
     73         tr[x<<1|1].new_len();
     74     }
     75     int mid=tr[x].get_mid();
     76     if(la>mid)
     77         update(x<<1|1,w,la,ra);
     78     else if(ra<=mid)
     79         update(x<<1,w,la,ra);
     80     else
     81     {
     82         update(x<<1,w,la,mid);
     83         update(x<<1|1,w,mid+1,ra);
     84     }
     85     
     86     int tmp=max(tr[x<<1].t_len,tr[x<<1|1].t_len);
     87     tr[x].t_len=max(tmp,tr[x<<1].r_len+tr[x<<1|1].l_len);
     88     tr[x].l_len=tr[x<<1].l_len;
     89     tr[x].r_len=tr[x<<1|1].r_len;
     90     
     91     if(tr[x<<1].t_len==tr[x<<1].get_len())
     92         tr[x].l_len+=tr[x<<1|1].l_len;
     93         
     94     if(tr[x<<1|1].t_len==tr[x<<1|1].get_len())
     95         tr[x].r_len+=tr[x<<1].r_len;
     96     return;
     97 }
     98 
     99 int main()
    100 {
    101     scanf("%d%d",&n,&m);
    102     build(1,1,n);
    103     while(m--)
    104     {
    105         int op;
    106         scanf("%d",&op);
    107         if(op==1)
    108         {
    109             int tot;
    110             scanf("%d",&tot);
    111             int ans=ask(tot,1);
    112             cout<<ans<<endl;//从头开始找
    113             if(ans)
    114                 update(1,1,ans,ans+tot-1);//标记已经住进去
    115         }
    116         else if(op==2)
    117         {
    118             int la,len;
    119             scanf("%d%d",&la,&len);
    120             update(1,0,la,la+len-1);//清空房间
    121         }
    122     }
    123     return 0;
    124 }
    View Code
  • 相关阅读:
    保存会话数据——cookie学习
    HttpServletRequest学习
    HttpServletResponse 学习
    Servlet学习
    Http协议简单学习笔记
    利用tomcat配置网站
    PHPCMS-V9 获取一级栏目、二级栏目、三级栏目
    PHP判断当前访问的是 微信、iphone、android 浏览器
    二维数组根据某个字段排序
    动物界的再生一个故事
  • 原文地址:https://www.cnblogs.com/Beckinsale/p/7586128.html
Copyright © 2011-2022 走看看