题目链接:点击打开链接
题目大意:
有一个长为n的空序列,有4种操作,
(1) 找到一个连续长为x的空序列,将其覆盖(尽量靠左),并输出覆盖的起点坐标
(2) 将包含x的那个块所在的序列重新清空,并输出free的起点和终点
(3) 得到序列中第x个块的起点,
(4) 将整个序列清空,
解题思路:
刚开始完全是蒙蔽的,其实第一个操作还很好说,就是跟一道名为 Hotel(POJ 3667) 的题差不多,但是操作 2 ,3 那是完全不会。想了几天,还是不知道怎么实现。
后来碰到一道扫描线的题目,想了想,好难啊,还是回头做这一道吧,然后考虑到每次他让你新建和删除的块是可以用数组记录下来的,就试了一下,果然可行,然后就 t 掉了。真的不会了,然后去网上找大佬的代码看,发现大佬用的二分+vector,我用数组在插入块那个地方是直接 sort ,不断的sort实在耗时,不过这 stl 更tm神奇,以前从来不知道vector还有这么多操作。插入 删除 反正vector都能实现,注意二分找位置就好,还有清空全部那个地方不要用 build 初始化,耗时,用 update 正常更新就行。细节看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define hash haha
using namespace std;
typedef long long ll;
int n,m;
char c[10];
struct nodes //vector的元素
{
int x,y;
};
vector<nodes> a;
bool cmp(const nodes &a,const nodes &b)
{
return a.x<b.x;
}
struct node
{
int l,r,mid; //记录左最长右最长和区间最长
int ls,rs,ms; //是否覆盖的标记和延迟标记
int cnt,lazy;
}t[200000];
void pushdown(int rt) //正常的区间合并pushdown
{
if(t[rt].lazy)
{
if(t[rt].cnt)
{
t[lson].ls=t[lson].rs=t[lson].ms=0;
t[rson].ls=t[rson].rs=t[rson].ms=0;
}
if(!t[rt].cnt)
{
t[lson].ls=t[lson].rs=t[lson].ms=t[lson].r-t[lson].l+1;
t[rson].ls=t[rson].rs=t[rson].ms=t[rson].r-t[rson].l+1;
}
t[lson].lazy=t[rson].lazy=t[rt].lazy;
t[lson].cnt=t[rson].cnt=t[rt].cnt;
t[rt].lazy=t[rt].cnt=0;
}
}
void pushup(int rt) //同上
{
if(t[lson].ls==t[lson].r-t[lson].l+1)
t[rt].ls=t[lson].ls+t[rson].ls;
else
t[rt].ls=t[lson].ls;
if(t[rson].rs==t[rson].r-t[rson].l+1)
t[rt].rs=t[lson].rs+t[rson].rs;
else
t[rt].rs=t[rson].rs;
t[rt].ms=max(max(t[lson].ms,t[rson].ms),t[lson].rs+t[rson].ls);
}
void build(int l,int r,int rt)
{
int mid=(l+r)>>1;
t[rt].l=l;t[rt].r=r;
t[rt].mid=mid;
t[rt].cnt=0;t[rt].lazy=0;
t[rt].ls=t[rt].rs=t[rt].ms=0;
if(l==r)
{
t[rt].ls=t[rt].rs=t[rt].ms=1;
return ;
}
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
void update(int l,int r,int flag,int rt) //正常的更新
{
if(l<=t[rt].l&&t[rt].r<=r)
{
t[rt].lazy=1;
t[rt].cnt=flag;
if(t[rt].cnt)
t[rt].ls=t[rt].rs=t[rt].ms=0;
else
t[rt].ls=t[rt].rs=t[rt].ms=t[rt].r-t[rt].l+1;
return ;
}
pushdown(rt);
if(l<=t[rt].mid)
update(l,r,flag,lson);
if(r>t[rt].mid)
update(l,r,flag,rson);
pushup(rt);
}
int query(int k,int rt) //查询满足最长连续区间的左端点
{
if(t[rt].l==t[rt].r)
return 1;
pushdown(rt);
if(t[lson].ms>=k)
return query(k,lson);
else if(t[lson].rs+t[rson].ls>=k)
return t[rt].mid-t[lson].rs+1;
else if(t[rson].ms>=k)
return query(k,rson);
pushup(rt);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
build(1,n,1);
a.clear(); //初始化vector
while(m--)
{
int q;
scanf(" %s",c);
if(c[0]=='N')
{
scanf("%d",&q);
if(t[1].ms>=q)
{
int st=query(q,1);
nodes k;
k.x=st;
k.y=st+q-1;
vector<nodes>::iterator it; //神奇的vector二分,不会,stl还是学的太烂了
it=upper_bound(a.begin(),a.end(),k,cmp);
a.insert(it,k); //找到位置然后插入
update(st,st+q-1,1,1); //更新
printf("New at %d\n",st);
}
else
printf("Reject New\n");
}
if(c[0]=='F')
{
scanf("%d",&q);
nodes k;
k.x=q;
k.y=q;
vector<nodes>::iterator it;
it=upper_bound(a.begin(),a.end(),k,cmp); //二分查找
int tmp=it-a.begin()-1;
if(tmp==-1||a[tmp].y<q) //如果没找到
printf("Reject Free\n");
else
{
update(a[tmp].x,a[tmp].y,0,1); //找到的话更新删除
printf("Free from %d to %d\n",a[tmp].x,a[tmp].y);
a.erase(a.begin()+tmp);
}
}
if(c[0]=='G')
{
scanf("%d",&q);
if(q<=(int)a.size()) //看是否有这么多元素
printf("Get at %d\n",a[q-1].x);
else
printf("Reject Get\n");
}
if(c[0]=='R')
{
a.clear(); //初始化队列
update(1,n,0,1);
printf("Reset Now\n");
}
}
printf("\n");
}
return 0;
}