上周六BC的最后一道题
感觉还是挺经典的做法的,首先因为是n的全排列,所以可以直接二分答案然后用线段树判断,好吧其实bc的题解说的已经很清楚了
这是一道良心的基础数据结构题。
我们二分a[k]的值,假设当前是mid,然后把大于mid的数字标为1,不大于mid的数字标为0。然后对所有操作做完以后检查一下a[k]位置上是0还是1。
因为只有两种值,所以操作还是不难做的。只要用一个线段树,支持区间求和、区间赋值即可。这样要排序一个区间时只要查询一下里面有几个1和几个0,然后把前半段赋值为0,后半段赋值为1即可(降序的话就是反过来)。
复杂度是O(mlog2n)的。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define maxn 100009
#define rep(i, j, k) for(int i = j; i <= k; i++)
using namespace std;
int n, m, k, f[maxn], tot[6 * maxn], all[maxn * 6];
int a[maxn], b[maxn], c[maxn], Ans;
void insert (int x, int lx, int rx, int position, int num)
{
if (position > rx || position < lx)
return;
if (lx == rx && lx == position)
{
tot[x] = num;
return;
}
int mid = (lx + rx) >> 1;
if (position <= mid)
insert (2 * x, lx, mid, position, num);
else
insert (2 * x + 1, mid + 1, rx, position, num);
tot[x] = tot[2 * x] + tot[2 * x + 1];
return;
}
void set (int x, int la, int ra, int L, int R, int num)
{
if (R < L)
return;
if (L > ra || R < la)
return;
if (L <= la && ra <= R)
{
all[x] = num;
tot[x] = num * (ra - la + 1);
return;
}
int mid = (la + ra) >> 1;
if (all[x] != -1)
{
all [2 * x] = all [2 * x + 1] = all [x], tot[x] = all[x] * (ra - la + 1);
tot[2 * x] = all[x] * (mid - la + 1);
tot[2 * x + 1] = all[x] * (ra - mid);
all [x] = -1;
}
set (2 * x, la, mid, L, R, num);
set (2 * x + 1, mid + 1, ra, L, R, num);
tot[x] = tot[2 * x] + tot[2 * x + 1];
return;
}
int ask (int x, int la, int ra, int L, int R)
{
if (L > ra || R < la)
return 0;
if (L <= la && ra <= R)
{
if (all[x] != -1)
tot[x] = all[x] * (ra - la + 1), all[x] = -1;
return tot[x];
}
int mid = (la + ra) >> 1;
if (all[x] != -1)
{
all[2 * x] = all[2 * x + 1] = all[x];
tot[2 * x] = all[x] * (mid - la + 1);
tot[2 * x + 1] = all[x] * (ra - mid);
all[x] = -1;
}
int num = ask (2 * x, la, mid, L, R) + ask (2 * x + 1, mid + 1, ra, L, R);
tot[x] = tot[2 * x] + tot[2 * x + 1];
return num;
}
void work ()
{
int l = 1, r = n;
while (l <= r)
{
memset (all, -1, sizeof (all));
memset (tot, 0, sizeof (tot));
int mid = (l + r) >> 1;
rep (i, 1, n)
insert (1, 1, n, i, f[i] >= mid ? 1 : 0);
rep (i, 1, m)
{
int now = ask (1, 1, n, b[i], c[i]);//the num of 1
int other = c[i] - b[i] + 1 - now;//the num of 0
if (a[i] == 0)
{
set (1, 1, n, b[i], b[i] + other - 1, 0);
set (1, 1, n, b[i] + other, c[i], 1);
}
else
{
set (1, 1, n, b[i], b[i] + now - 1, 1);
set (1, 1, n, b[i] + now, c[i], 0);
}
}
if (ask (1, 1, n, k, k) > 0)
l = mid + 1, Ans = mid;
else
r = mid - 1;
}
printf ("%d\n", Ans);
return ;
}
int main()
{
int Case;
scanf("%d", &Case);
while (Case--)
{
scanf ("%d%d", &n, &m);
rep (i, 1, n)
scanf ("%d", &f[i]);
rep (i, 1, m)
scanf ("%d%d%d", &a[i], &b[i], &c[i]);
scanf ("%d", &k);
work ();
}
return 0;
}