Address
Solution
- 好像没什么人写树状数组套主席树,其实常数挺小的说……
- 前三个都是基础操作了,而对于前驱后继,我们可以拆成两个操作,先算它在区间中排名,再查找对应的值。
- 空间上因为重复节点很多,稍微卡卡也能过了。
- 时间复杂度
O(nlog2n)
O
(
n
log
2
n
)
。
Code(洛谷)
#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
using namespace std;
namespace inout
{
const int S = 1 << 20;
char frd[S], *ihed = frd + S;
const char *ital = ihed;
inline char inChar()
{
if (ihed == ital)
fread(frd, 1, S, stdin), ihed = frd;
return *ihed++;
}
inline int get()
{
char ch; int res = 0; bool flag = false;
while (!isdigit(ch = inChar()) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (isdigit(ch = inChar()))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
char fwt[S], *ohed = fwt;
const char *otal = ohed + S;
inline void outChar(char ch)
{
if (ohed == otal)
fwrite(fwt, 1, S, stdout), ohed = fwt;
*ohed++ = ch;
}
inline void put(int x)
{
if (x > 9) put(x / 10);
outChar(x % 10 + 48);
}
};
using namespace inout;
const int L = 1e8;
const int M = 2e7 + 5, N = 5e4 + 5;
int rt[N], a[N], lx[N], rx[N], low[N];
int ql, qr, n, m, T, tmp; bool flag;
struct Chairman
{
int lc, rc, cnt;
#define l(x) tr[x].lc
#define r(x) tr[x].rc
#define c(x) tr[x].cnt
}tr[M];
inline void Init(int l, int r)
{
ql = qr = 0;
for (int i = l - 1; i; i -= low[i])
lx[++ql] = rt[i];
for (int i = r; i; i -= low[i])
rx[++qr] = rt[i];
}
inline void ChangeL()
{
for (int i = 1; i <= ql; ++i)
lx[i] = l(lx[i]);
for (int i = 1; i <= qr; ++i)
rx[i] = l(rx[i]);
}
inline void ChangeR()
{
for (int i = 1; i <= ql; ++i)
lx[i] = r(lx[i]);
for (int i = 1; i <= qr; ++i)
rx[i] = r(rx[i]);
}
inline void Insert(int &x, int l, int r, int v)
{
if (!x)
x = ++T, l(x) = r(x) = c(x) = 0;
++c(x);
if (l == r) return ;
int mid = l + r >> 1;
if (v <= mid) Insert(l(x), l, mid, v);
else Insert(r(x), mid + 1, r, v);
}
inline void Modify(int x, int l, int r, int v)
{
--c(x);
if (l == r) return ;
int mid = l + r >> 1;
if (v <= mid) Modify(l(x), l, mid, v);
else Modify(r(x), mid + 1, r, v);
}
inline int queryKth(int l, int r, int v)
{
if (l == r)
{
int res = 0;
if (flag)
{
for (int i = 1; i <= ql; ++i)
res -= c(lx[i]);
for (int i = 1; i <= qr; ++i)
res += c(rx[i]);
}
return res;
}
int mid = l + r >> 1;
if (v <= mid)
return ChangeL(), queryKth(l, mid, v);
else
{
int res = 0;
for (int i = 1; i <= ql; ++i)
res -= c(l(lx[i]));
for (int i = 1; i <= qr; ++i)
res += c(l(rx[i]));
return ChangeR(), res + queryKth(mid + 1, r, v);
}
}
inline int findKth(int l, int r, int k)
{
if (l == r) return l;
int res = 0;
for (int i = 1; i <= ql; ++i)
res -= c(l(lx[i]));
for (int i = 1; i <= qr; ++i)
res += c(l(rx[i]));
int mid = l + r >> 1;
if (k <= res)
return ChangeL(), findKth(l, mid, k);
else
return ChangeR(), findKth(mid + 1, r, k - res);
}
int main()
{
n = get(); m = get();
for (int i = 1; i <= n; ++i) low[i] = i & -i;
for (int i = 1; i <= n; ++i)
{
a[i] = get();
for (int j = i; j <= n; j += low[j])
Insert(rt[j], 0, L, a[i]);
}
int opt, l, r, k;
while (m--)
{
opt = get(); l = get(); r = get();
switch (opt)
{
case 1:
flag = false; Init(l, r);
put(queryKth(0, L, get()) + 1), outChar('\n');
break;
case 2:
Init(l, r);
put(findKth(0, L, get())), outChar('\n');
break;
case 3:
for (int i = l; i <= n; i += low[i])
Modify(rt[i], 0, L, a[l]);
a[l] = r;
for (int i = l; i <= n; i += low[i])
Insert(rt[i], 0, L, a[l]);
break;
case 4:
flag = false; Init(l, r);
tmp = queryKth(0, L, k = get());
if (!tmp)
outChar('-'), put(2147483647), outChar('\n');
else
Init(l, r), put(findKth(0, L, tmp)), outChar('\n');
break;
case 5:
flag = true; Init(l, r);
tmp = queryKth(0, L, k = get());
if (tmp == r - l + 1)
put(2147483647), outChar('\n');
else
Init(l, r), put(findKth(0, L, tmp + 1)), outChar('\n');
break;
}
}
fwrite(fwt, 1, ohed - fwt, stdout);
return 0;
}