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 ",ans); 116 update(ans,ans+x-1,1,1); 117 } 118 else 119 { 120 printf("0 "); 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 }