【USACO 2013 1月金组】seating
时间限制: 1 Sec 内存限制: 128 MB
题目描述
为了赚更多的钱,奶牛场开了一间专门做奶昔的餐馆。这个餐馆有N个位子(1<=N<=500000)排成一行,开始时,位子都是空的。
每天,有M个不同的事件按次序发生(1<=M<=300000).事件分为两类:
1.举办一个party,这个party有p头奶牛(1<=p<=N),这p头奶牛只会坐在相邻的位子。如果没有p个连续的空位,则奶牛们会离开。如果有多个,奶牛们会选择起点编号最小的一段空位。
2.区间[a,b]的奶牛们离开座位。(1<=a
输入
第一行:两个整数N,M。
第二行到第M+1行:每一行表示一个事件,它要么是形如“A p”,表示有一个party,这个party有p头奶牛;要么是形如L a b 的一行,表示区间[a,b]的所有奶牛全部离开。
输出
一行,表示不满足要求的聚会个数。
样例输入
10 4
A 6
L 2 4
A 5
A 2
样例输出
1
解题报告:
某天考试题。。。
比较裸的线段树题目,关键在于代码实现有点难(考试时没调出来)
用线段树控制区间的删除与增加,
每个线段树上节点,维护3个变量le,max,re。
struct Node{
int l,r;
int le,re,max;
int lz;
}nodes[MAXN*5];
他们分别表示该区间内部靠左的空间大小,区间中不与左右空区间接触的最大空区间大小,该区间内部靠右的空区间大小。
每次updata操作这样写:
inline void updata(int u){
nodes[u].max=maxf(nodes[u<<1].max,nodes[(u<<1)+1].max);
nodes[u].max=maxf(nodes[u].max,nodes[u<<1].re+nodes[(u<<1)+1].le);
le[u]=nodes[u<<1].le;
re[u]=nodes[(u<<1)+1].re;
if(nodes[u<<1].le==nodes[u<<1].r-nodes[u<<1].l+1)
le[u]+=nodes[(u<<1)+1].le;
if(nodes[(u<<1)+1].re==nodes[(u<<1)+1].r-nodes[(u<<1)+1].l+1)
re[u]+=nodes[u<<1].re;
}
lazy标记保存三个值,非别是0,1,2
代表无操作,填满和清空
const int REMOVE=2;
const int FILL=1;
下传lazy时这么写:
inline void pushdown(int index){
nodes[index<<1].lz=nodes[(index<<1)+1].lz=nodes[index].lz;
if(nodes[index].lz==FILL){
nodes[index<<1].le=nodes[index<<1].re=nodes[index<<1].max=0;
nodes[(index<<1)+1].le=nodes[(index<<1)+1].re=nodes[(index<<1)+1].max=0;
}
else if(nodes[index].lz==REMOVE){
nodes[index<<1].max=nodes[index<<1].re=nodes[index<<1].le
=nodes[index<<1].r-nodes[index<<1].l+1;
nodes[(index<<1)+1].max=nodes[(index<<1)+1].re=nodes[(index<<1)+1].le
=nodes[(index<<1)+1].r-nodes[(index<<1)+1].l+1;
}
nodes[index].lz=0;
}
由于每次A操作要寻找一段最靠左长度为len的空区间
因此多添加一个函数:
int len;
int query(int u){
if(nodes[u].l==nodes[u].r)return nodes[u].l;
if(nodes[u].lz)
pushdown(u);
if(nodes[u<<1].max>=len)return query(u<<1);
else if(nodes[u<<1].re+nodes[(u<<1)+1].le>=len)
return nodes[u<<1].r-nodes[u<<1].re+1;
else return query((u<<1)+1);
}
此函数用于寻找长度为len的空区间左端点位置
原理:在保持当前区间中最大空区间长度大于len时尽量向左儿子前进,最后找到的一定是最靠左的区间。
下面发AC代码:
#include<cstdio>
const int MAXN=510000;
const int MAXM=310000;
const int REMOVE=2;
const int FILL=1;
inline int max(const int &a,const int &b)
{return a<b?b:a;}
inline int min(const int &a,const int &b)
{return a<b?a:b;}
inline void getint(int &t){
register char c;t=0;
do{c=getchar();}while(c<'0'||c>'9');
while(c<='9'&&c>='0'){t=t*10+c-'0';c=getchar();}
}
struct Node{
int l,r;
int le,re,max;
int lz;
}nodes[MAXN*5];
inline void pushdown(int index){
nodes[index<<1].lz=nodes[(index<<1)+1].lz=nodes[index].lz;
if(nodes[index].lz==FILL){
nodes[index<<1].le=nodes[index<<1].re=nodes[index<<1].max=0;
nodes[(index<<1)+1].le=nodes[(index<<1)+1].re=nodes[(index<<1)+1].max=0;
}
else if(nodes[index].lz==REMOVE){
nodes[index<<1].max=nodes[index<<1].re=nodes[index<<1].le
=nodes[index<<1].r-nodes[index<<1].l+1;
nodes[(index<<1)+1].max=nodes[(index<<1)+1].re=nodes[(index<<1)+1].le
=nodes[(index<<1)+1].r-nodes[(index<<1)+1].l+1;
}
nodes[index].lz=0;
}
inline void updata(int u){
nodes[u].max=max(nodes[u<<1].max,nodes[(u<<1)+1].max);
nodes[u].max=max(nodes[u].max,nodes[u<<1].re+nodes[(u<<1)+1].le);
nodes[u].le=nodes[u<<1].le;
nodes[u].re=nodes[(u<<1)+1].re;
if(nodes[u<<1].le==nodes[u<<1].r-nodes[u<<1].l+1)
nodes[u].le+=nodes[(u<<1)+1].le;
if(nodes[(u<<1)+1].re==nodes[(u<<1)+1].r-nodes[(u<<1)+1].l+1)
nodes[u].re+=nodes[u<<1].re;
}
void build(int u,int l,int r){
nodes[u].l=l;
nodes[u].r=r;
nodes[u].le=nodes[u].re=nodes[u].max=r-l+1;
if(l==r)return ;
int mid=(l+r)>>1;
build(u<<1,l,mid);
build((u<<1)+1,mid+1,r);
}
int l,r,k;
void fill(int u){
if(nodes[u].r<l||nodes[u].l>r)return ;
if(nodes[u].lz)
pushdown(u);
if(nodes[u].l>=l&&nodes[u].r<=r){
nodes[u].lz=k;
if(k==REMOVE)nodes[u].le=nodes[u].re=nodes[u].max=nodes[u].r-nodes[u].l+1;
else nodes[u].le=nodes[u].re=nodes[u].max=0;
return ;
}
fill(u<<1);
fill((u<<1)+1);
updata(u);
}
int len;
int query(int u){
if(nodes[u].l==nodes[u].r)return nodes[u].l;
if(nodes[u].lz)
pushdown(u);
if(nodes[u<<1].max>=len)return query(u<<1);
else if(nodes[u<<1].re+nodes[(u<<1)+1].le>=len)
return nodes[u<<1].r-nodes[u<<1].re+1;
else return query((u<<1)+1);
}
int main(){
int n,m;
getint(n),getint(m);
build(1,1,n);
int ans=0;
register char o;
register int a,b,c;
for(int i=1;i<=m;i++){
while((o=getchar())!='L'&&o!='A');
if(o=='L'){
getint(a);
getint(b);
l=a;
r=b;
k=REMOVE;
fill(1);
}else {
getint(c);
if(c>nodes[1].max){ans++;continue;}
len=c;
int pos=query(1);
l=pos;
r=pos+c-1;
k=FILL;
fill(1);
}
}
printf("%d\n",ans);
}
//ORZ GJY LJH TSY SYK YLY GMR YMX
此题在bzoj上每个点给了10秒的时限,但是在学校oj上只给一秒。。。
于是就成了卡常神题 = =
我从两天前开始就是一阵狂T,把能想到的inline,读入优化,等等全部写上,再把函数参数全改成全局变量,
结果是这样的:
心酸呐= =
然后只好在群里求助大神,大神说加个注释就能保证卡过!
于是加上:
//ORZ GJY LJH TSY SYK YLY GMR YMX
然后果然交了两发就过了啊哈哈哈