P2894 [USACO08FEB]Hotel G

P2894 [USACO08FEB]Hotel G

传送门:https://www.luogu.com.cn/problem/P2894

题意:

参考样例,第一行输入n,m ,n代表有n个房间,编号为1---n,开始都为空房,m表示以下有m行操作,以下 每行先输入一个数 i ,表示一种操作:

若i为1,表示查询房间,再输入一个数x,表示在1--n 房间中找到长度为x的连续空房,输出连续x个房间中左端的房间号,尽量让这个房间号最小,若找不到长度为x的连续空房,输出0,并且在这x个空房间中住上人。

若i为2,表示退房,再输入两个数 x,y 代表 房间号 x---x+y-1 退房,即让房间为空。

日均一棵树,有益身心健康 hhhhh

区间操作,我们用线段树来处理

刚开始所有位置都是0

两个操作,一个查询是否有n个连续的0,如果有,把他们再变成1

第二个 把x到x+y-1变成0

常规的用线段树维护和啊最值啊什么的是不行的了

这是一道 区间合并问题 (解决一段连续区间修改,查询问题)

然后我们想啊该如何维护起始点与最大的连续区间长度

有三种情况

第一种

我们假设要找的这个连续区间是在树维护的那段区间的左边

也就是说,是以最左边为这个连续区间的起点

第二种

我们假设要找的这个连续区间是在树维护的那段区间的中间

第三种

我们假设要找的这个连续区间是在树维护的那段区间的右边

我们就可以用线段树维护 左端连续区间长度ls、右端连续区间长度rs,最大连续长度sum

重点在于push_up操作

每次push_up是从俩儿子到父亲的过程

我们想,父亲的ls是咋来的呢

两种情况

 第一种,是来自左儿子的全部和右儿子的ls

第二种,仅来自左儿子的ls

然后rs同理

 最后这种情况当然就是来自左儿子rs的和右儿子的ls啦

因为最后的这种情况不需要保留(对他的父亲无影响),我们的sum维护的还是最大连续长度,所以sum对这三种情况取大

最后解释一下参数叭

struct node 
{
    int l(区间左端点),r(区间右端点),lazy(是否被标记),ls(左端连续区间长度),rs(左端连续区间长度),sum(最大连续长度);
}tree[maxn*4];
build(int l(左端点),int r(右端点),int now(当前编号))
push_up(int now(当前编号))
push_down(int now(当前编号))
void update(int l(区间左端点),int r(区间右端点),int now(当前编号),int tag(指令是1还是2))
int query(int l(区间左端点),int r(区间右端点),int now(当前编号),int len(要找的连续的多长的0))


 
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define lowbit(a) ((a)&-(a))
  5 #define clean(a,b) memset(a,b,sizeof(a))
  6 const int mod = 1e9 + 7;
  7 const int inf=0x3f3f3f3f;
  8 const int maxn = 5e4+10;
  9  
 10 int _;
 11  
 12 /////////////////////////////////////////////////////////////////////////////////////////
 13 struct node 
 14 {
 15     int l,r,lazy,ls,rs,sum;
 16 }tree[maxn*4];
 17 //维护连续的0的个数
 18 void build(int l,int r,int now)
 19 {
 20     tree[now].l=l;
 21     tree[now].r=r;
 22     tree[now].lazy=0;
 23     tree[now].ls=tree[now].rs=tree[now].sum=r+1-l;
 24     if(l==r) return ;
 25     int mid=(l+r)>>1;
 26     build(l,mid,now<<1);
 27     build(mid+1,r,now<<1|1);
 28 }
 29 void push_up(int now)
 30 {
 31     if(tree[now<<1].sum==(tree[now<<1].r-tree[now<<1].l+1))
 32     {
 33         tree[now].ls=(tree[now<<1].r-tree[now<<1].l+1)+tree[now<<1|1].ls;
 34     }
 35     else 
 36     {
 37         tree[now].ls=tree[now<<1].ls;
 38     }
 39     if(tree[now<<1|1].sum==(tree[now<<1|1].r-tree[now<<1|1].l+1))
 40     {
 41         tree[now].rs=(tree[now<<1|1].r-tree[now<<1|1].l+1)+tree[now<<1].rs;
 42     }
 43     else 
 44     {
 45         tree[now].rs=tree[now<<1|1].rs;
 46     }
 47     tree[now].sum=max(tree[now<<1].rs+tree[now<<1|1].ls,max(tree[now<<1].sum,tree[now<<1|1].sum));
 48 }
 49 void push_down(int now)
 50 {
 51     if(tree[now].lazy==0) return ;
 52     else if(tree[now].lazy==1) 
 53     {
 54         tree[now<<1].sum=tree[now<<1].ls=tree[now<<1].rs=0;
 55         tree[now<<1|1].sum=tree[now<<1|1].ls=tree[now<<1|1].rs=0;
 56         tree[now<<1].lazy=tree[now<<1|1].lazy=1;
 57     }
 58     else if(tree[now].lazy==2)
 59     {
 60         tree[now<<1].sum=tree[now<<1].ls=tree[now<<1].rs=tree[now<<1].r-tree[now<<1].l+1;
 61         tree[now<<1|1].sum=tree[now<<1|1].ls=tree[now<<1|1].rs=tree[now<<1|1].r-tree[now<<1|1].l+1;
 62         tree[now<<1].lazy=tree[now<<1|1].lazy=2;
 63     }
 64     tree[now].lazy=0;
 65 }
 66 void update(int l,int r,int now,int tag)//L R 要修改的区间 tag=1 0->1 tag=2 1->0
 67 {
 68     if(tree[now].l==l&&tree[now].r==r)
 69     {
 70         if(tag==1) tree[now].sum=tree[now].ls=tree[now].rs=0;
 71         else if(tag==2) tree[now].sum=tree[now].ls=tree[now].rs=r-l+1;
 72         tree[now].lazy=tag;
 73         return ;
 74     }
 75     push_down(now);
 76     int mid=(tree[now].l+tree[now].r)>>1;
 77     if(r<=mid) update(l,r,now<<1,tag);
 78     else if(mid<l) update(l,r,now<<1|1,tag);
 79     else 
 80     {
 81         update(l,mid,now<<1,tag);
 82         update(mid+1,r,now<<1|1,tag);
 83     }
 84     push_up(now);
 85 }
 86 int query(int l,int r,int now,int len)
 87 {
 88     if(l==r) return l;
 89     push_down(now);
 90     int mid=(l+r)>>1;
 91     if(tree[now<<1].sum>=len) return query(l,mid,now<<1,len);
 92     else if(tree[now<<1].rs+tree[now<<1|1].ls>=len) return mid-tree[now<<1].rs+1;
 93     else return query(mid+1,r,now<<1|1,len);
 94 }
 95 /////////////////////////////////////////////////////////////////////////////////////////
 96 
 97 int main()
 98 {
 99     // freopen("in.in","r",stdin);
100     // freopen("out.out","w",stdout);
101     int n,m;
102     scanf("%d%d",&n,&m);
103     build(1,n,1);
104     for(int i=1;i<=m;i++)
105     {//tag=1 0->1 tag=2 1->0
106         int num;
107         scanf("%d",&num);
108         if(num==1) 
109         {
110             int x;
111             scanf("%d",&x);
112             if(tree[1].sum>=x)
113             {
114                 int ans=query(1,n,1,x);
115                 printf("%d\n",ans);
116                 update(ans,ans+x-1,1,1);
117             }
118             else 
119             {
120                 printf("0\n");
121             }
122         }
123         else if(num==2)
124         {
125             int x,y;
126             scanf("%d%d",&x,&y);
127             update(x,x+y-1,1,2);
128         }
129     }
130     return 0;
131 }

猜你喜欢

转载自www.cnblogs.com/YangKun-/p/12763386.html