P2894 [USACO08FEB]Hotel G
作者:互联网
written on 2022-05-14
写这篇题解的原因是cpp说我基础太烂,于是找几题巩固。
一道巩固线段树基础的好题。同P3071好评。
审完题后,发现有许多区间操作,所以很明显是用数据结构维护,维护的过程都不难,因此普通线段树即可维护。
要注意的点就是,为了找连续区间的长度,我们的操作就是再维护两个数组 \(L,R\) ,在转移时用这两个值来更新 \(val\) 。另外,在询问答案时,从三种情况考虑:
-
答案在左区间
-
答案在右区间
-
答案跨越两个区间
就这样按序扫过来,就能知道最左端的解了。
Code
#include<bits/stdc++.h>
#define N 50005
using namespace std;
int n,m;
struct Seg
{
int L[N<<2],R[N<<2],val[N<<2];
int tag[N<<2];
void push_up(int p,int l,int r)
{
int mid=l+r>>1;
L[p]=L[p<<1],R[p]=R[p<<1|1];
if(L[p<<1]==mid-l+1) L[p]+=L[p<<1|1];
if(R[p<<1|1]==r-mid) R[p]+=R[p<<1];
val[p]=max(R[p<<1]+L[p<<1|1],max(val[p<<1],val[p<<1|1]));
}
void build(int p,int l,int r)
{
tag[p]=-1;
if(l==r)
{
L[p]=R[p]=val[p]=1;
return ;
}
int mid=l+r>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
push_up(p,l,r);
}
void spread(int p,int l,int r)
{
if(tag[p]==-1) return ;
int mid=l+r>>1;
val[p<<1]=L[p<<1]=R[p<<1]=tag[p]*(mid-l+1);
val[p<<1|1]=L[p<<1|1]=R[p<<1|1]=tag[p]*(r-mid);
tag[p<<1]=tag[p<<1|1]=tag[p];
tag[p]=-1;
}
void update(int p,int l,int r,int nl,int nr,int v)
{
if(nl<=l&&nr>=r)
{
val[p]=L[p]=R[p]=v*(r-l+1),tag[p]=v;
return ;
}
spread(p,l,r);
int mid=l+r>>1;
if(nl<=mid) update(p<<1,l,mid,nl,nr,v);
if(nr>mid) update(p<<1|1,mid+1,r,nl,nr,v);
push_up(p,l,r);
}
int ask(int p,int l,int r,int k)
{
if(l==r) return l;
spread(p,l,r);
int mid=l+r>>1;
if(val[p<<1]>=k) return ask(p<<1,l,mid,k);
if(R[p<<1]+L[p<<1|1]>=k) return mid-R[p<<1]+1;
if(val[p<<1|1]>=k) return ask(p<<1|1,mid+1,r,k);
}
}t1;
int main()
{
scanf("%d%d",&n,&m);
t1.build(1,1,n);
for(int i=1;i<=m;i++)
{
int op,x,y;
scanf("%d%d",&op,&x);
if(op==1)
{
if(t1.val[1]<x)
{
puts("0");
continue;
}
int pos=t1.ask(1,1,n,x);
printf("%d\n",pos);
t1.update(1,1,n,pos,pos+x-1,0);
}
else
{
scanf("%d",&y);
t1.update(1,1,n,x,x+y-1,1);
}
}
}
标签:return,val,int,Hotel,区间,USACO08FEB,答案,P2894,维护 来源: https://www.cnblogs.com/Freshair-qprt/p/16537766.html