【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=4552
【题解】
线段树的一些特殊技巧:合并与分裂。
首先把每个点都建出一棵权值线段树,每次排序时,将包含的权值线段树合并在一起即可。可以用set维护当前的线段树集合。
但是排序可能会将两端的线段树分开,这时就要进行分裂操作,形象一点,就是将线段树从中间切开,在切割的地方新增一条节点,然后原来的分给左边,新的给右边。
由于线段树合并的总复杂度是 O(节点个数) O ( 节 点 个 数 ) ,每次分裂最多增加 O(2logN) O ( 2 l o g N ) 个节点,所以总复杂度是 O(N∗logN) O ( N ∗ l o g N ) 。
【代码】
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj4552]
Points : segment tree
- - - - - - - - - - - - - - - */
# include
# define ll long long
# define inf 0x3f3f3f3f
# define N 100010
# define K 50
using namespace std;
typedef pair <int, int> pr;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
struct Tree{
int pl, pr, num;
}T[N * K];
set mp;
int rt[N], n , m, place, tag[N];
int extend(int p, int num, int l, int r){
if (!p) p = ++place;
T[p].num++;
if (l != r){
int mid = (l + r) / 2;
if (mid >= num)
T[p].pl = extend(T[p].pl, num, l, mid);
else T[p].pr = extend(T[p].pr, num, mid + 1, r);
}
return p;
}
void splitmn(int &pl, int &pr, int num, int l, int r){
pr = ++place;
if (l == r){
T[pr].num = T[pl].num - num;
T[pl].num = num;
return;
}
if (T[T[pl].pl].num == num){
T[pr].pr = T[pl].pr, T[pl].pr = 0;
}
else {
int mid = (l + r) / 2;
if (T[T[pl].pl].num < num)
splitmn(T[pl].pr, T[pr].pr, num - T[T[pl].pl].num, mid + 1, r);
else {
T[pr].pr = T[pl].pr; T[pl].pr = 0;
splitmn(T[pl].pl, T[pr].pl, num, l, mid);
}
}
T[pl].num = T[T[pl].pl].num + T[T[pl].pr].num;
T[pr].num = T[T[pr].pl].num + T[T[pr].pr].num;
}
void splitmx(int &pl, int &pr, int num, int l, int r){
pr = ++place;
if (l == r){
T[pr].num = T[pl].num - num;
T[pl].num = num;
return;
}
if (T[T[pl].pr].num == num){
T[pr].pl = T[pl].pl, T[pl].pl = 0;
}
else {
int mid = (l + r) / 2;
if (T[T[pl].pr].num < num)
splitmx(T[pl].pl, T[pr].pl, num - T[T[pl].pr].num, l, mid);
else {
T[pr].pl = T[pl].pl; T[pl].pl = 0;
splitmx(T[pl].pr, T[pr].pr, num, mid + 1, r);
}
}
T[pl].num = T[T[pl].pl].num + T[T[pl].pr].num;
T[pr].num = T[T[pr].pl].num + T[T[pr].pr].num;
}
int merge(int pl, int pr, int l, int r){
if (pl == 0) return pr;
if (pr == 0) return pl;
T[pl].num = T[pl].num + T[pr].num;
if (l != r){
int mid = (l + r) / 2;
T[pl].pl = merge(T[pl].pl, T[pr].pl, l, mid);
T[pl].pr = merge(T[pl].pr, T[pr].pr, mid + 1, r);
}
return pl;
}
int query(int p, int num, int l, int r){
if (l == r) return l;
int mid = (l + r) / 2;
if (T[T[p].pl].num >= num) return query(T[p].pl, num, l, mid);
else return query(T[p].pr, num - T[T[p].pl].num, mid + 1, r);
}
int main(){
freopen("bzoj4552.in", "r", stdin);
freopen("bzoj4552.out", "w", stdout);
n = read(), m = read();
int L = 1, R = n;
for (int i = 1; i <= n; i++){
int x = read();
rt[i] = extend(rt[i], x, L, R);
tag[i] = 0;
mp.insert(make_pair(i, i));
}
for (int i = 1; i <= m; i++){
int op = read(), l = read(), r = read(), thl, thr;
set :: iterator it = mp.lower_bound(make_pair(l, 0));
if (it == mp.end() || (*it).first > l) it--;
thl = (*it).first, thr = (*it).second;
if (thl != l){
if (tag[thl] == 0){
splitmn(rt[thl], rt[l], (l - 1) - thl + 1, L, R);
tag[l] = 0;
}
else {
splitmx(rt[thl], rt[l], (l - 1) - thl + 1, L, R);
tag[l] = 1;
}
mp.erase(it);
mp.insert(make_pair(thl, l - 1));
mp.insert(make_pair(l, thr));
}
it = mp.lower_bound(make_pair(r, 0));
if (it == mp.end() || (*it).first > r) it--;
thl = (*it).first, thr = (*it).second;
if (r != thr){
if (tag[thl] == 0){
splitmn(rt[thl], rt[r + 1], r - thl + 1, L, R);
tag[r + 1] = 0;
}
else {
splitmx(rt[thl], rt[r + 1], r - thl + 1, L, R);
tag[r + 1] = 1;
}
mp.erase(it);
mp.insert(make_pair(thl, r));
mp.insert(make_pair(r + 1, thr));
}
it = mp.lower_bound(make_pair(l, 0));
if (it == mp.end() || (*it).first > l) it--;
int now = (*it).second + 1, nex;
mp.erase(it);
for (; now <= r; now = nex + 1){
it = mp.lower_bound(make_pair(now, 0));
nex = (*it).second;
rt[l] = merge(rt[l], rt[now], L, R);
rt[now] = 0;
mp.erase(it);
}
tag[l] = op;
mp.insert(make_pair(l, r));
}
int q = read();
set :: iterator it = mp.begin();
while ((*it).second - (*it).first + 1 < q){
q -= (*it).second - (*it).first + 1;
it++;
}
if (tag[(*it).first] == 1)
q = (*it).second - (*it).first + 1 - q + 1;
printf("%d\n", query(rt[(*it).first], q, L, R));
return 0;
}