题目链接
这个题是集训是讲的模板题,但是我没(mei)听(you)懂(ting),于是做题时比较惨,卡了不少时间。最后想:
struct Node
{
int l, r;
int sum;//记录该区间内的最大空余连续区间
int add;//延迟标记
bool flag;//全空标记
int ls, rs;//记录该区间中,最大空余前缀、后缀/
}tr[N<<2];
于是我们的pushup操作可以是:
void pushup(int p)
{
tr[p].sum =max(max(tr[p<<1].sum, tr[p<<1|1].sum), tr[p<<1].rs + tr[p<<1|1].ls);
//该区间的最大空余连续区间,应该是max(左孩子最大连续区间, 右孩子最大连续区间, 左孩子最大后缀+右孩子最大前缀)
tr[p].ls = tr[p<<1].ls;
tr[p].rs = tr[p<<1|1].rs;
//默认该区间最大前缀为其左孩子最大前缀,后缀同理
tr[p].flag = tr[p<<1].flag && tr[p<<1|1].flag;
//左孩子右孩子均全空
if (tr[p<<1].flag) tr[p].ls = tr[p<<1].sum + tr[p<<1|1].ls;
if (tr[p<<1|1].flag) tr[p].rs = tr[p<<1|1].sum + tr[p<<1].rs;
//如果左孩子全空,那么最大前缀还可能是:左孩子区间长度+右孩子前缀,
//后缀同理
}
下面是ac代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#define ll long long
using namespace std;
const int N =1e5+5;
struct Node
{
int l, r;
int sum;
int add;
bool flag;
int ls, rs;
}tr[N<<2];
int mx;
void build(int p, int l, int r)
{
mx = max(mx, p);
tr[p].l = l; tr[p].r = r;
tr[p].add = -1;
tr[p].flag = 1;
if (l == r)
{
tr[p].sum = tr[p].ls = tr[p].rs = 1;
return;
}
int mid = (l + r) >>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
tr[p].ls = tr[p].rs = tr[p].sum = tr[p<<1].sum + tr[p<<1|1].sum;
}
void spread(int p)
{
if (tr[p].add == -1) return;
int l = p<<1, r = p<<1|1;
tr[l].sum = tr[l].ls = tr[l].rs = tr[p].add * (tr[l].r - tr[l].l + 1);
tr[r].sum = tr[r].ls = tr[r].rs = tr[p].add * (tr[r].r - tr[r].l + 1);
tr[l].add = tr[r].add = tr[p].add;
tr[l].flag = tr[r].flag = tr[p].add;
tr[p].add = -1;
}
void pushup(int p)
{
tr[p].sum =max(max(tr[p<<1].sum, tr[p<<1|1].sum), tr[p<<1].rs + tr[p<<1|1].ls);
tr[p].ls = tr[p<<1].ls;
tr[p].rs = tr[p<<1|1].rs;
tr[p].flag = tr[p<<1].flag && tr[p<<1|1].flag;
if (tr[p<<1].flag) tr[p].ls = tr[p<<1].sum + tr[p<<1|1].ls;
if (tr[p<<1|1].flag) tr[p].rs = tr[p<<1|1].sum + tr[p<<1].rs;
}
void change(int p, int l, int r, bool flag)
{
if (l <= tr[p].l && r >= tr[p].r)
{
tr[p].sum = tr[p].ls = tr[p].rs = flag * (tr[p].r - tr[p].l + 1);
tr[p].add = flag;
tr[p].flag = flag;
return;
}
spread(p);
int mid = (tr[p].r + tr[p].l) >> 1;
if (l <= mid) change(p<<1, l, r, flag);
if (r > mid) change(p<<1|1, l, r, flag);
pushup(p);
}
int ask(int p, int k)
{
if (tr[p].l == tr[p].r)
{
if (k > tr[p].sum) return 0;
return tr[p].l;
}
int mid = (tr[p].l + tr[p].r) >> 1;
spread(p);
if (tr[p<<1].sum >= k) return ask(p<<1, k);
if (tr[p<<1].rs + tr[p<<1|1].ls >= k) return mid - tr[p<<1].rs + 1;
else if (tr[p<<1|1].sum >= k) return ask(p<<1|1, k);
return 0;
}
void print()
{
for (int i = 1; i <= mx; i++)
{
cout << tr[i].l << " " << tr[i].r << " " << tr[i].sum << endl;
cout << tr[i].ls << " " << tr[i].rs << " " << tr[i].flag << endl;
cout << "--------" << endl;
}
cout << "------------------------" << endl;
}
int main()
{
int n, m;
cin >> n >> m;
build(1, 1, n);
// print();
while(m--)
{
int op;
scanf("%d", &op);
if (op == 1)
{
int k;
scanf("%d", &k);
int gg = ask(1, k);
if (gg)
change(1, gg, gg + k -1, 0);
// print();
printf("%d\n", gg);
}
else
{
int l, r;
scanf("%d%d", &l, &r);
change(1, l, r +l - 1, 1);
// print();
}
}
return 0;
}