题解 P2894 【[USACO08FEB]酒店Hotel】
Setsugesuka · · 题解
暴力出奇迹,如果暴力没有AC,那我们就去卡常。
在仔细观察题目后,我们发现题目需要我们维护以下两种操作。
1.给定一个正整数
D ,找到一个左端点最小且它的大小\geq D 全0 区间,我们假设找到的这个区间为[l,r] ,我们需要将[l,l+d-1] 赋值为1 ,[l+d,r] 赋值为0 。2.给定两个正整数
X D ,我们需要将区间[x,x+d-1] 赋值为0 。
不难发现,操作
首先,对于操作
inline void assignval(int l,int r,int v=0)
{
set<node>::iterator itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert(node(l,r,v));
}
考虑操作
inline void add(int sum)
{
set<node>::iterator itl,itr;
itl=s.begin();
bool pd=false;
while(itl!=s.end())
{
if(itl->v==1)
{
++itl;
continue;
}
itr=itl;
while(itr!=s.end()&&itr->v==0)
{
++itr;
}
bool ccpd=false;
if(itr==s.end())
ccpd=true;
--itr;
if(itr->r-itl->l+1>=sum)
{
pd=true;
break;
}
if(ccpd)
{
break;
}
itl=itr;
++itl;
}
if(pd==false)
puts("0");
else
{
int l=itl->l,r=itr->r;
write(l);
putchar('\n');
s.erase(itl,++itr);
s.insert(node(l,l+sum-1,1));
if(r-l+1!=sum)
{
s.insert(node(l+sum,r,0));
}
}
}
因为我们使用了双指针进行求解,显然这样的操作是
难道我们真的只能用线段树来写线段树裸题了吗?虽然线段树代码量小,实现简单,复杂度具有保证,但喜欢暴力的我显然是不会去选择线段树的,考虑优化我们的
为什么我们的算法会这么慢呢?我们不难发现,因为我们推平操作的暴力性,使得程序在运行过程中显然会出现这样的一个情况。
是的,由于我们每次都是暴力地新建一个节点,代表我们
于是,我们不难写出如下合并代码,并将它放到别的操作里。
inline void merge(int l)
{
set<node>::iterator it1,it2,it3;
it2=s.lower_bound(l);
if(it2==s.begin())
return;
it1=it2,it3=it2;
it1--,++it3;
bool pd3=(it3!=s.end());
if(pd3&&it1->v==it2->v&&it2->v==it3->v&&it1->v==it3->v)
{
int l=it1->l,r=it3->r,v=it2->v;
s.erase(it1,++it3);
s.insert(node(l,r,v));
}
else if(it1->v==it2->v)
{
int l=it1->l,r=it2->r,v=it2->v;
s.erase(it1,++it2);
s.insert(node(l,r,v));
}
else if(pd3&&it2->v==it3->v)
{
int l=it2->l,r=it3->r,v=it2->v;
s.erase(it2,++it3);
s.insert(node(l,r,v));
}
}
需要注意的是,如果我们当前取出来的节点已经是
幸运的是,我们成功地把看不到跑了多少秒的
现在我们只需要对几毫秒进行优化了,不难想到去卡常。
首先我们注意到,这个题目的读入的数据比较大,于是我们用
当然,我们还可以对很多的细节进行优化,比如
// luogu-judger-enable-o2
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
template <class T>
inline void write(T x)
{
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
inline char nc()
{
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &sum)
{
char ch=nc();
int tf=0;
sum=0;
while((ch<'0'||ch>'9')&&(ch!='-')) ch=nc();
tf=((ch=='-')&&(ch=nc()));
while(ch>='0'&&ch<='9') sum=sum*10+(ch-48),ch=nc();
(tf)&&(sum=-sum);
}
const int MAXN=50010;
struct node
{
mutable int l,r,v;
node(int L,int R=-1,int V=0):l(L),r(R),v(V) {}
bool operator<(const node &o) const
{
return l<o.l;
}
};
set<node> s;
inline void check()
{
for(set<node>::iterator it=s.begin();it!=s.end();++it)
{
for(int j=1;j<=(it->r-it->l+1);++j)
{
cout<<it->v<<" ";
}
}
cout<<endl;
}
inline void merge(int l)
{
set<node>::iterator it1,it2,it3;
it2=s.lower_bound(l);
if(it2==s.begin())
return;
it1=it2,it3=it2;
it1--,++it3;
bool pd3=(it3!=s.end());
if(pd3&&it1->v==it2->v&&it2->v==it3->v&&it1->v==it3->v)
{
int l=it1->l,r=it3->r,v=it2->v;
s.erase(it1,++it3);
s.insert(node(l,r,v));
}
else if(it1->v==it2->v)
{
int l=it1->l,r=it2->r,v=it2->v;
s.erase(it1,++it2);
s.insert(node(l,r,v));
}
else if(pd3&&it2->v==it3->v)
{
int l=it2->l,r=it3->r,v=it2->v;
s.erase(it2,++it3);
s.insert(node(l,r,v));
}
}
inline set<node>::iterator split(int pos)
{
set<node>::iterator it=s.lower_bound(node(pos));
if(it!=s.end()&&it->l==pos) return it;
--it;
int L=it->l,R=it->r,V=it->v;
s.erase(it);
s.insert(node(L,pos-1,V));
return s.insert(node(pos,R,V)).first;
}
inline void assignval(int l,int r,int v=0)
{
set<node>::iterator itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert(node(l,r,v));
merge(l);
}
inline void add(int sum)
{
set<node>::iterator itl,itr;
itl=s.begin();
bool pd=false;
while(itl!=s.end())
{
if(itl->v==1)
{
++itl;
continue;
}
itr=itl;
while(itr!=s.end()&&itr->v==0)
{
++itr;
}
bool ccpd=false;
if(itr==s.end())
ccpd=true;
--itr;
if(itr->r-itl->l+1>=sum)
{
pd=true;
break;
}
if(ccpd)
{
break;
}
itl=itr;
++itl;
}
if(pd==false)
puts("0");
else
{
int l=itl->l,r=itr->r;
write(l);
putchar('\n');
s.erase(itl,++itr);
s.insert(node(l,l+sum-1,1));
if(r-l+1!=sum)
{
s.insert(node(l+sum,r,0));
}
merge(l);
}
}
int n,m;
int main()
{
read(n),read(m);
s.insert(node(1,n,0));
while(m--)
{
int op,x,y;
read(op);
if(op==1)
{
read(x);
add(x);
}
else if(op==2)
{
read(x),read(y);
assignval(x,x+y-1,0);
}
}
return 0;
}
在加了这些优化之后,我们就可以用
999毫秒极限过题