挺基础的一个线段树题目,两种操作, 第二种就是区间和, 第一种的话起始下标也很容易得到, 主要是终点下标需要思考一下, 我的做法是记录下当前剩余多少花还没放, 然后找到第一个剩余花小于当前区间总空位的个数的区间, 然后根据左子区间的剩余情况再递归直到叶子节点, 线段树每个节点维护三个统计量空位的个数第一个空位最后一个空位, 以及一个lazy标记。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N = 50005;
#define lch rt << 1, L, mid
#define rch rt << 1 | 1, mid + 1, R
struct SegmentTree {
int idx[N << 2], cnt[N << 2], lazy[N << 2], last[N << 2];
int n, st, ed, rem;
void init(int n) {
this->n = n;
build(1, 0, n - 1);
}
void build(int rt, int L, int R) {
idx[rt] = L, lazy[rt] = -1, cnt[rt] = R - L + 1, last[rt] = R;
if (L == R) {
return;
}
int mid = L + R >> 1;
build(lch);
build(rch);
}
inline void push_up(int rt) {
cnt[rt] = cnt[rt << 1 | 1] + cnt[rt << 1];
if (cnt[rt << 1] > 0)
idx[rt] = idx[rt << 1];
else if (cnt[rt << 1 | 1] > 0)
idx[rt] = idx[rt << 1 | 1];
else
idx[rt] = -1;
if (cnt[rt << 1 | 1] > 0)
last[rt] = last[rt << 1 | 1];
else if (cnt[rt << 1] > 0)
last[rt] = last[rt << 1];
else
last[rt] = -1;
}
inline void push_down(int rt, int L, int R) {
if (lazy[rt] != -1) {
int mid = L + R >> 1;
if (lazy[rt]) {
cnt[rt << 1] = 0;
cnt[rt << 1 | 1] = 0;
idx[rt << 1] = -1;
idx[rt << 1 | 1] = -1;
lazy[rt << 1] = lazy[rt << 1 | 1] = 1;
last[rt << 1] = last[rt << 1 | 1] = -1;
}
else {
cnt[rt << 1] = mid - L + 1;
cnt[rt << 1 | 1] = R - mid;
idx[rt << 1] = L;
idx[rt << 1 | 1] = mid + 1;
lazy[rt << 1] = lazy[rt << 1 | 1] = 0;
last[rt << 1] = mid, last[rt << 1 | 1] = R;
}
lazy[rt] = -1;
}
}
int update(int rt, int L, int R, int l, int r) {
if (l <= L && R <= r) {
lazy[rt] = 0;
int tmp = R - L + 1 - cnt[rt];
idx[rt] = L, cnt[rt] = R - L + 1;
last[rt] = R;
return tmp;
}
int mid = L + R >> 1;
push_down(rt, L, R);
int res = 0;
if (l <= mid)
res += update(lch, l, r);
if (r > mid)
res += update(rch, l, r);
push_up(rt);
return res;
}
int gao(int rt, int L, int R) {
if (L == R) {
rem = 0;
cnt[rt] = 0, idx[rt] = -1, last[rt] = -1;
return L;
}
int mid = L + R >> 1;
push_down(rt, L, R);
int res;
if (cnt[rt << 1] >= rem)
res = gao(lch);
else {
rem -= cnt[rt << 1];
cnt[rt << 1] = 0, idx[rt << 1] = -1, last[rt] = -1;
lazy[rt << 1] = 1;
res = gao(rch);
}
push_up(rt);
return res;
}
void modify(int rt, int L, int R, int l) {
if (L >= l) {
if (rem <= 0 || cnt[rt] == 0) return;
if (st == -1 && cnt[rt] > 0) {
st = idx[rt];
}
if (R == n - 1) {
if (rem > cnt[rt])
rem = cnt[rt];
if (cnt[rt])
ed = gao(rt, L, R);
}
else {
if (rem > cnt[rt]) {
rem -= cnt[rt];
cnt[rt] = 0, idx[rt] = -1;
lazy[rt] = 1;
ed = last[rt];
last[rt] = -1;
}
else {
if (cnt[rt])
ed = gao(rt, L, R);
}
}
return;
}
int mid = L + R >> 1;
push_down(rt, L, R);
if (l <= mid)
modify(lch, l);
if (R >= l)
modify(rch, l);
push_up(rt);
}
void op1(int p, int c) {
rem = c, st = -1, ed = -1;
modify(1, 0, n - 1, p);
}
int op2(int l, int r) {
return update(1, 0, n - 1, l, r);
}
}T;
int main() {
int test, n, m, op, l, r, p, f;
scanf("%d", &test);
while (test--) {
scanf("%d%d", &n, &m);
T.init(n);
for (int i = 0; i < m; i++) {
scanf("%d", &op);
if (op == 1) {
scanf("%d%d", &p, &f);
T.op1(p, f);
if (T.st == -1)
puts("Can not put any one.");
else {
printf("%d %d\n", T.st, T.ed);
}
}
else {
scanf("%d%d", &l, &r);
printf("%d\n", T.op2(l, r));
}
}
puts("");
}
return 0;
}