[ZJOI2007] 报表统计 题解
Description
Solution
显然是道 DS。
想到建两个个平衡树。一个用来维护所有数的最小差值,插入 \(x\) 时,找到 \(x\) 的前驱和后继更新答案即可。
另一个用来维护相邻数的最小差值。假设操作时在 \(k\) 后插入 \(x\),那么 \(lst[k]\) 和 \(a[k+1]\) 就不再相邻,需要删除,然后插入 \(|lst[k]-x|\) 和 \(|x-a[k+1]|\),然后将 \(lst[k]\) 更新。
用 Splay 写就可以做到均摊 \(O(\log n)\),总复杂度 \(O((n+m)\log n)\),但有个巨大的常数,所以不开 O2 过不了。(用 multiset 可过)
Code
Splay
#include <bits/stdc++.h>
#ifdef ORZXKR
#include <debug.h>
#else
#define debug(...) 1
#endif
using namespace std;
namespace FASTIO {
char ibuf[1 << 21], *p1 = ibuf, *p2 = ibuf;
char getc() {
return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
template<class T> bool read(T &x) {
x = 0; int f = 0; char ch = getc();
while (ch < '0' || ch > '9') f |= ch == '-', ch = getc();
while (ch >= '0' && ch <= '9') x = (x * 10) + (ch ^ 48), ch = getc();
x = (f ? -x : x); return 1;
}
bool read(char &x) {
while ((x = getc()) == ' ' || x == '\n' || x == '\r');
return x != EOF;
}
bool read(char *x) {
while ((*x = getc()) == '\n' || *x == ' ' || *x == '\r');
if (*x == EOF) return 0;
while (!(*x == '\n' || *x == ' ' || *x == '\r' || *x == EOF)) *(++x) = getc();
*x = 0;
return 1;
}
template<typename A, typename ...B> bool read(A &x, B &...y) { return read(x) && read(y...); }
char obuf[1 << 21], *o1 = obuf, *o2 = obuf + (1 << 21) - 1;
void flush() { fwrite(obuf, 1, o1 - obuf, stdout), o1 = obuf; }
void putc(char x) { *o1++ = x; if (o1 == o2) flush(); }
template<class T> void write(T x) {
if (!x) putc('0');
if (x < 0) x = -x, putc('-');
char c[40]; int tot = 0;
while (x) c[++tot] = x % 10, x /= 10;
for (int i = tot; i; --i) putc(c[i] + '0');
}
void write(char x) { putc(x); }
template<typename A, typename ...B> void write(A x, B ...y) { write(x), write(y...); }
struct Flusher {
~Flusher() { flush(); }
} flusher;
} // namespace FASTIO
using FASTIO::read; using FASTIO::putc; using FASTIO::write;
const int kMaxN = 2e6 + 5;
class Splay {
/********** Need **********
* Insert
* Delete
* GetPre
* GetNext
* GetMin
********** Need **********/
public:
int newnode(int x) {
val[++tot] = x, sz[tot] = cnt[tot] = 1;
return tot;
}
void pushup(int x) {
sz[x] = sz[ch[x][0]] + cnt[x] + sz[ch[x][1]];
}
int get(int x) {
return x == ch[fa[x]][1];
}
void clear(int x) {
sz[x] = cnt[x] = val[x] = ch[x][0] = ch[x][1] = fa[x] = 0;
}
void rotate(int x) {
int fl = get(x), y = fa[x], z = fa[y];
ch[y][fl] = ch[x][fl ^ 1];
if (ch[x][fl ^ 1]) fa[ch[x][fl ^ 1]] = y;
ch[x][fl ^ 1] = y;
if (z) ch[z][get(y)] = x;
fa[y] = x, fa[x] = z;
pushup(y), pushup(x);
}
void splay(int x) {
for (int y = fa[x]; y = fa[x], y; rotate(x)) {
if (fa[y]) rotate(get(x) == get(y) ? y : x);
}
rt = x;
}
void ins(int x) {
if (!rt) {
rt = newnode(x), pushup(rt);
return ;
}
for (int cur = rt, f = 0; ; ) {
if (val[cur] == x) {
++cnt[cur], pushup(cur), pushup(f);
return splay(cur);
}
f = cur;
cur = ch[cur][val[cur] < x];
if (!cur) {
cur = newnode(x), fa[cur] = f, ch[f][val[f] < x] = cur;
pushup(cur), pushup(f);
return splay(cur);
}
}
}
int getrk(int x) {
int ret = 0;
for (int cur = rt; cur; ) {
if (x < val[cur]) {
cur = ch[cur][0];
} else if (x == val[cur]) {
ret += sz[ch[cur][0]] + 1, splay(cur);
return ret;
} else {
ret += sz[ch[cur][0]] + cnt[cur];
cur = ch[cur][1];
}
}
}
void _getpre() {
int cur;
for (cur = ch[rt][0]; ch[cur][1]; cur = ch[cur][1]) {}
return splay(cur);
}
void del(int x) {
getrk(x);
if (cnt[rt] > 1) {
--cnt[rt];
return pushup(rt);
}
if (!ch[rt][0] && !ch[rt][1]) {
clear(rt), rt = 0;
return ;
} else if (!ch[rt][0]) {
int tmp = rt;
rt = ch[rt][1], fa[rt] = 0;
return clear(tmp);
} else if (!ch[rt][1]) {
int tmp = rt;
rt = ch[rt][0], fa[rt] = 0;
return clear(tmp);
}
int tmp = rt;
_getpre();
fa[ch[tmp][1]] = rt, ch[rt][1] = ch[tmp][1];
return clear(tmp), pushup(rt);
}
int getpre(int x) {
ins(x);
if (cnt[rt] > 1) return del(x), x;
if (!ch[rt][0]) return del(x), -1;
int ret, cur;
for (cur = ch[rt][0]; ch[cur][1]; cur = ch[cur][1]) {}
ret = val[cur], splay(cur);
del(x);
return ret;
}
int getnxt(int x) {
ins(x);
if (cnt[rt] > 1) return del(x), x;
if (!ch[rt][1]) return del(x), -1;
int ret, cur;
for (cur = ch[rt][1]; ch[cur][0]; cur = ch[cur][0]) {}
ret = val[cur], splay(cur);
del(x);
return ret;
}
int getmin() {
int cur;
if (!ch[rt][0]) return val[rt];
for (cur = ch[rt][0]; ch[cur][0]; cur = ch[cur][0]) {}
return val[cur];
}
private:
int rt, tot, sz[kMaxN], cnt[kMaxN], val[kMaxN], ch[kMaxN][2], fa[kMaxN];
} s1, s2;
int n, m, ans2;
int a[kMaxN], b[kMaxN];
vector<int> v[kMaxN];
int main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
read(n, m);
for (int i = 1; i <= n; ++i) {
read(a[i]);
b[i] = a[i];
v[i].emplace_back(b[i]);
s1.ins(a[i]);
if (i > 1) s2.ins(abs(a[i] - a[i - 1]));
}
ans2 = INT_MAX;
sort(b + 1, b + 1 + n);
for (int i = 1; i < n; ++i) {
ans2 = min(ans2, b[i + 1] - b[i]);
}
while (m--) {
char op[10]; int x, k;
read(op);
if (op[0] == 'I') { // INSERT
read(x, k);
int lst = v[x][v[x].size() - 1], pre = s1.getpre(k), nxt = s1.getnxt(k);
if (x != n) s2.del(abs(a[x + 1] - lst)), s2.ins(abs(k - a[x + 1]));
s2.ins(abs(k - lst));
v[x].emplace_back(k);
if (~pre) ans2 = min(ans2, k - pre);
if (~nxt) ans2 = min(ans2, nxt - k);
s1.ins(k);
} else if (op[4] == 'G') { // MIN_GAP
write(s2.getmin(), '\n');
} else { // MIN_SORT_GAP
write(ans2, '\n');
}
}
return 0;
}
multiset
#include <bits/stdc++.h>
#ifdef ORZXKR
#include <debug.h>
#else
#define debug(...) 1
#endif
using namespace std;
namespace FASTIO {
char ibuf[1 << 21], *p1 = ibuf, *p2 = ibuf;
char getc() {
return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
template<class T> bool read(T &x) {
x = 0; int f = 0; char ch = getc();
while (ch < '0' || ch > '9') f |= ch == '-', ch = getc();
while (ch >= '0' && ch <= '9') x = (x * 10) + (ch ^ 48), ch = getc();
x = (f ? -x : x); return 1;
}
bool read(char &x) {
while ((x = getc()) == ' ' || x == '\n' || x == '\r');
return x != EOF;
}
bool read(char *x) {
while ((*x = getc()) == '\n' || *x == ' ' || *x == '\r');
if (*x == EOF) return 0;
while (!(*x == '\n' || *x == ' ' || *x == '\r' || *x == EOF)) *(++x) = getc();
*x = 0;
return 1;
}
template<typename A, typename ...B> bool read(A &x, B &...y) { return read(x) && read(y...); }
char obuf[1 << 21], *o1 = obuf, *o2 = obuf + (1 << 21) - 1;
void flush() { fwrite(obuf, 1, o1 - obuf, stdout), o1 = obuf; }
void putc(char x) { *o1++ = x; if (o1 == o2) flush(); }
template<class T> void write(T x) {
if (!x) putc('0');
if (x < 0) x = -x, putc('-');
char c[40]; int tot = 0;
while (x) c[++tot] = x % 10, x /= 10;
for (int i = tot; i; --i) putc(c[i] + '0');
}
void write(char x) { putc(x); }
template<typename A, typename ...B> void write(A x, B ...y) { write(x), write(y...); }
struct Flusher {
~Flusher() { flush(); }
} flusher;
} // namespace FASTIO
using FASTIO::read; using FASTIO::putc; using FASTIO::write;
const int kMaxN = 5e5 + 5;
int n, m, ans2;
int a[kMaxN], b[kMaxN];
vector<int> v[kMaxN];
multiset<int> s1, s2;
int main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
read(n, m);
for (int i = 1; i <= n; ++i) {
read(a[i]);
b[i] = a[i];
v[i].emplace_back(a[i]), s1.emplace(a[i]);
}
ans2 = 1e9;
sort(b + 1, b + 1 + n);
for (int i = 1; i <= n - 1; ++i) {
s2.emplace(abs(a[i + 1] - a[i]));
ans2 = min(ans2, abs(b[i + 1] - b[i]));
}
while (m--) {
char op[10]; int x, k;
read(op);
if (op[0] == 'I') { // INSERT
read(x, k);
int lst = v[x][v[x].size() - 1];
auto it = s1.lower_bound(k);
if (it != s1.end()) ans2 = min(ans2, *it - k);
if (it != s1.begin()) --it, ans2 = min(ans2, k - *it);
auto ii = s2.lower_bound(abs(a[x + 1] - lst));
if (ii != s2.end()) s2.erase(ii);
s2.emplace(abs(k - lst));
if (x != n) s2.emplace(abs(k - a[x + 1]));
s1.emplace(k), v[x].emplace_back(k);
} else if (op[4] == 'G') { // MIN_GAP
write(*s2.begin(), '\n');
} else { // MIN_SORT_GAP
write(ans2, '\n');
}
}
return 0;
}