题目大意:给出n个点从0~n-1排成一条线,然后又m条命令,k=1就是从某个点开始插多少话进去,k=2就是把l到r之间的花扔掉。。换成程序员的语言就是k=1就查询第一个插入点和最后一个插入点,k=2就查询区间插了多少花。
查询差了多少花没什么难度,关键是找第一个和最后一个插入点,显然用二分查找。
#include <iostream>
#include <string.h>
#include<algorithm>
#include <cstdio>
using namespace std;
#define lc n << 1
#define rc n << 1 | 1
const int maxn = 50010;
struct seg {
int l, r, sum;//节点sum存这段区间还有多少空位,或说能插多少花
int lazy;
}t[maxn << 2];
inline int len(int n) { return t[n].r - t[n].l + 1; }
inline void push_up(int n)
{
t[n].sum = t[lc].sum + t[rc].sum;
}
inline void push_down(int n)
{
int x = t[n].lazy;
t[lc].sum = (x == 1 ? 0 : len(lc));
t[rc].sum = (x == 1 ? 0 : len(rc));
t[lc].lazy = t[rc].lazy = x;
t[n].lazy = 0;
}
void build(int n, int l, int r)
{
t[n].l = l;t[n].r = r;t[n].lazy = 0;
if (l == r)
{
t[n].sum = 1;
return;
}
int mid = (l + r) >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
push_up(n);
}
void update(int n, int l, int r,int a)//a=1是插花,a=-1是扔花
{
if (l > t[n].r || r < t[n].l)return;
if (l <= t[n].l&&r >= t[n].r)
{
t[n].sum = (a == 1 ? 0 : len(n));
t[n].lazy = a;
return;
}
if (t[n].lazy)
push_down(n);
update(lc, l, r, a);
update(rc, l, r, a);
push_up(n);
}
int query(int n, int l, int r)
{
if (l > t[n].r || r < t[n].l)
return 0;
if (l <= t[n].l&&r >= t[n].r)
return t[n].sum;
if (t[n].lazy != 0)push_down(n);
return query(lc, l, r) + query(rc, l, r);
}
void solve(int l,int r, int f)
{
int x = query(1, l, r);//先查询从l开始一共能插多少花
if (x == 0)
{
cout << "Can not put any one." << endl;
return;
}
else if (x < f) { f = x; }//这一步很关键!去除之后会错,原因看二分部分
int ql = l, qr = r, mid;
while (ql != qr)//找第一个插入点
{
mid = (ql + qr) >> 1;
x = query(1, ql, mid);
if (x >= 1)
qr = mid;
else
ql = mid + 1;
}
cout << ql << ' ';
ql = l, qr = r;
while (ql != qr)//找最后一个
{
mid = (ql + qr) >> 1;
x = query(1, ql, mid);
if (x >= f)//因为这一句话所以f要等于min(f,x)
{
qr = mid;
}
else
{
update(1, ql, mid, 1);
f -= x;//如果左子树的sum<f那么把左子树插满花
ql = mid + 1;
}
}
update(1, qr, qr, 1);//qr这个点可能没更新到
printf("%d\n",qr);
}
int main()
{
int T, n, m, c, f, b;
cin >> T;
while (T--)
{
scanf("%d%d",&n,&m);
build(1, 0, n - 1);
while (m--)
{
scanf("%d%d%d",&c,&b,&f);
if (c == 1)solve(b, n - 1, f);
else
{
int q = query(1, b, f);
printf("%d\n",(f - b + 1) - q);
update(1, b, f, -1);
}
}
printf("\n");
}
return 0;
}