[ZJOI2007] 报表统计 题解

Description

link

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;
}
posted @ 2022-10-13 17:08  下蛋爷  阅读(24)  评论(0编辑  收藏  举报