分析:
本题纠结了好多天,又用一下午时间找bug,换思路,终于终于做出来了。极为有毒的一题,相当于把三种线段树类型的题出成了一道,四种操作:
①找出最小的x长度区间并覆盖;
②删除某点x所处的区间;
③找出第x个区间的开始位置;
④清除所有区间;
分析发现:
对于④就是操作多次②
对于②:需要把①的每个区间记录下来,反向操作①
对于①:由于各个区间之间没有重叠,不需要用lazy数组储存向下更新,甚至也不需要向上更新,知道这点可以简化代码。另外对于空白区间的存储最初想是存最大区间的起始点(后来发现很蠢,行不通),改成了经典的左右最大区间,还是这样方便查询。
对于③:实际上是找第几大的问题(好像有博客说可以用STL中的二分函数找,不太清楚),反正我是通过又在原先的线段树上增加参数,记录区间内目标数的多少,基础的点操作。
最后吐槽这题的复杂操作,真是考察耐心,有一点点小错误就要几百行代码找bug,而且还多组输入输出,每组间还要回车也是服,个人建议如果不是特别闲的时候尽量不要做这题,真的能做崩溃o(≧口≦)o
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 200050;
const int inf = 0x7fffffff;
struct Node
{
int l;
int r;
};
int n, m;
int mmax[maxn], lmax[maxn], rmax[maxn], belong[maxn], have[maxn];
int x, ql, qr, qv, presum;
vector<Node>neww;
set<int>reset;
void init()
{
neww.clear();
reset.clear();
}
void build(int o, int l, int r)
{
lmax[o] = rmax[o] = mmax[o] = r - l + 1;
belong[o] = have[o] = 0;
if (l == r)return;
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
}
void update(int o, int l, int r)
{
if (ql <= l&&r <= qr)
{
belong[o] = qv;
if (qv == 0)lmax[o] = rmax[o] = mmax[o] = r - l + 1;
else lmax[o] = rmax[o] = mmax[o] = 0;
return;
}
int mid = (l + r) >> 1, lo = o << 1, ro = o << 1 | 1;
if (ql <= mid)update(lo, l, mid);
if (qr>mid) update(ro, mid + 1, r);
lmax[o] = lmax[lo];
if (lmax[lo] == mid - l + 1)lmax[o] += lmax[ro];
rmax[o] = rmax[ro];
if (rmax[ro] == r - mid)rmax[o] += rmax[lo];
mmax[o] = max(rmax[lo] + lmax[ro], max(mmax[lo], mmax[ro]));
}
void add(int o, int l, int r)
{
if (l == r)
{
have[o] = qv ? 1 : 0;
return;
}
int mid = (l + r) >> 1;
if (ql <= mid)add(o << 1, l, mid);
else add(o << 1 | 1, mid + 1, r);
have[o] = have[o << 1] + have[o << 1 | 1];
}
int query_new(int o, int l, int r)
{
if (l == r)return l;
int mid = (l + r) >> 1, lo = o << 1, ro = o << 1 | 1;
if (mmax[lo] >= x)return query_new(lo, l, mid);
if (rmax[lo] + lmax[ro] >= x)return mid - rmax[lo] + 1;
return query_new(ro, mid + 1, r);
}
int query_free(int o, int l, int r)
{
if (belong[o])return belong[o];
if (l == r)return 0;
int mid = (l + r) >> 1;
if (x <= mid)return query_free(o << 1, l, mid);
return query_free(o << 1 | 1, mid + 1, r);
}
int query_get(int o, int l, int r)
{
if (l == r)return l;
int mid = (l + r) >> 1, lo = o << 1, ro = o << 1 | 1;
if (presum + have[lo] >= x)return query_get(lo, l, mid);
presum += have[lo];
return query_get(ro, mid + 1, r);
}
void delet()
{
qv = 0;
update(1, 1, n);
add(1, 1, n);
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
build(1, 1, n);
init();
while (m--)
{
char op[10];
scanf(" %s", op);
if (op[0] == 'N')
{
scanf("%d", &x);
if (mmax[1]<x)printf("Reject New\n");
else
{
ql = query_new(1, 1, n);
qr = ql + x - 1;
neww.push_back((Node){ ql, qr });
qv = neww.size();
update(1, 1, n);
add(1, 1, n);
printf("New at %d\n", ql);
}
}
else if (op[0] == 'F')
{
scanf("%d", &x);
qv = query_free(1, 1, n);
if (qv == 0)printf("Reject Free\n");
else
{
reset.insert(qv);
ql = neww[qv - 1].l;
qr = neww[qv - 1].r;
delet();
printf("Free from %d to %d\n", ql, qr);
}
}
else if (op[0] == 'G')
{
scanf("%d", &x);
if (have[1]<x)printf("Reject Get\n");
else
{
presum = 0;
printf("Get at %d\n", query_get(1, 1, n));
}
}
else if (op[0] == 'R')
{
for (int len = neww.size(), i = 0; i<len; i++)
{
if (reset.find(i + 1) == reset.end())
{
ql = neww[i].l;
qr = neww[i].r;
delet();
}
}
printf("Reset Now\n");
init();
}
}
printf("\n");
}
return 0;
}