【BZOJ3946】无聊的游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/82459587

【题目链接】

【思路要点】

  • a i 表示 s i s i 1 l c p 的长度,对一段区间 [ l , r ] 增加一个前缀,那么 a l + 1 , a l + 2 , . . . , a r 都会对应增加这个前缀的长度, a l a r + 1 需要重新计算。
  • 用线段树套可持久化 T r e a p 维护 s ,在 T r e a p 中维护部分的哈希值,重新计算时先二分长度,比较哈希值即可。
  • 时间复杂度 O ( M L o g 2 N + M L o g N L o g L )

【代码】


#include<bits/stdc++.h>

using namespace std;
const int MAXN = 5e4 + 5;
const int MAXS = 6e5 + 5;
const int MAXP = 8e6 + 5;
const int INF = 1e9;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
  x = 0; int f = 1;
  char c = getchar();
  for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
  x *= f;
}
template <typename T> void write(T x) {
  if (x < 0) x = -x, putchar('-');
  if (x > 9) write(x / 10);
  putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
  write(x);
  puts("");
}
struct Treap {
  struct Node {
      int lc, rc;
      unsigned index;
      int size, l, r; ull Hash;
  } a[MAXP];
  unsigned seed;
  int size, len, sum;
  char s[MAXS]; ull bit[MAXS], Hash[MAXS];
  unsigned Rand() {
      seed = seed * seed + rand();
      return seed;
  }
  void init() {
      sum = 0;
      size = 0;
      seed = 1;
      bit[0] = 1;
      for (int i = 1; i < MAXS; i++)
          bit[i] = bit[i - 1] * 27;
  }
  ull gethash(int l, int r) {
      int len = r - l + 1;
      return Hash[r] - Hash[l - 1] * bit[len];
  }
  void update(int x) {
      a[x].size = a[x].r - a[x].l + 1;
      a[x].Hash = gethash(a[x].l, a[x].r);
      if (a[x].lc) {
          int tmp = a[x].lc;
          a[x].size += a[tmp].size;
          a[x].Hash += a[tmp].Hash * bit[a[x].r - a[x].l + 1];
      }
      if (a[x].rc) {
          int tmp = a[x].rc;
          a[x].size += a[tmp].size;
          a[x].Hash *= bit[a[tmp].size];
          a[x].Hash += a[tmp].Hash;
      }
  }
  int merge(int x, int y) {
      if (x == 0 || y == 0) return x + y;
      if (a[x].index < a[y].index) {
          int ans = ++size;
          a[ans] = a[x];
          a[ans].rc = merge(a[ans].rc, y);
          update(ans);
          return ans;
      } else {
          int ans = ++size;
          a[ans] = a[y];
          a[ans].lc = merge(x, a[ans].lc);
          update(ans);
          return ans;
      }
  }
  int load() {
      scanf("\n%s", s + sum + 1);
      len = strlen(s + sum + 1);
      int ans = ++size;
      a[ans].size = len;
      a[ans].l = sum + 1;
      a[ans].r = sum + len;
      a[ans].index = Rand();
      for (int i = sum + 1; i <= sum + len; i++)
          Hash[i] = Hash[i - 1] * 27 + s[i] - 'a' + 1;
      a[ans].Hash = gethash(sum + 1, sum + len);
      sum += len;
      return ans;
  }
  int length(int root) {
      return a[root].size;
  }
  ull calc(int root, int lft) {
      if (a[root].size == lft) return a[root].Hash;
      if (a[a[root].lc].size >= lft) return calc(a[root].lc, lft);
      ull ans = a[a[root].lc].Hash;
      lft -= a[a[root].lc].size;
      int len = a[root].r - a[root].l + 1;
      if (lft <= len) return ans * bit[lft] + gethash(a[root].l, a[root].l + lft - 1);
      else return ans * bit[lft] + gethash(a[root].l, a[root].r) * bit[lft - len] + calc(a[root].rc, lft - len);
  }
  int lcp(int x, int y) {
      int l = 0, r = min(a[x].size, a[y].size);
      while (l < r) {
          int mid = (l + r + 1) / 2;
          if (calc(x, mid) == calc(y, mid)) l = mid;
          else r = mid - 1;
      }
      return l;
  }
} Treap;
struct SegmentTree {
  struct Node {
      int lc, rc;
      int root, add, Min;
  } a[MAXN * 2];
  int root, size, n, last;
  void update(int root) {
      a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min);
  }
  void build(int &root, int l, int r) {
      root = ++size;
      a[root].add = 0;
      a[root].Min = 0;
      if (l == r) {
          a[root].root = Treap.load();
          if (last != 0) a[root].Min = Treap.lcp(a[root].root, a[last].root);
          last = root;
          return;
      }
      int mid = (l + r) / 2;
      build(a[root].lc, l, mid);
      build(a[root].rc, mid + 1, r);
      update(root);
  }
  void pushdown(int root, bool type) {
      if (a[root].lc) {
          int tmp = a[root].lc;
          a[tmp].Min += a[root].add, a[tmp].add += a[root].add;
          if (type) a[tmp].root = Treap.merge(a[root].root, a[tmp].root);
      }
      if (a[root].rc) {
          int tmp = a[root].rc;
          a[tmp].Min += a[root].add, a[tmp].add += a[root].add;
          if (type) a[tmp].root = Treap.merge(a[root].root, a[tmp].root);
      }
      a[root].add = 0; if (type) a[root].root = 0;
  }
  void init(int x) {
      root = size = 0;
      last = 0; n = x;
      build(root, 1, n);
  }
  void access(int root, int l, int r, int pos) {
      if (l == r) {
          last = root;
          return;
      }
      pushdown(root, true);
      int mid = (l + r) / 2;
      if (mid >= pos) access(a[root].lc, l, mid, pos);
      else access(a[root].rc, mid + 1, r, pos);
  }
  int query(int root, int l, int r, int ql, int qr) {
      if (l == ql && r == qr) return a[root].Min;
      int mid = (l + r) / 2;
      pushdown(root, false);
      if (mid >= qr) return query(a[root].lc, l, mid, ql, qr);
      else if (mid + 1 <= ql) return query(a[root].rc, mid + 1, r, ql, qr);
      else return min(query(a[root].lc, l, mid, ql, mid), query(a[root].rc, mid + 1, r, mid + 1, qr));
  }
  int query(int l, int r) {
      access(root, 1, n, l);
      int ans = Treap.length(a[last].root);
      if (l != r) chkmin(ans, query(root, 1, n, l + 1, r));
      return ans;
  }
  void modify(int root, int l, int r, int ql, int qr, int rt) {
      if (l == ql && r == qr) {
          a[root].root = Treap.merge(rt, a[root].root);
          return;
      }
      pushdown(root, true);
      int mid = (l + r) / 2;
      if (mid >= qr) modify(a[root].lc, l, mid, ql, qr, rt);
      else if (mid + 1 <= ql) modify(a[root].rc, mid + 1, r, ql, qr, rt);
      else modify(a[root].lc, l, mid, ql, mid, rt), modify(a[root].rc, mid + 1, r, mid + 1, qr, rt);
  }
  void add(int root, int l, int r, int ql, int qr, int len) {
      if (l == ql && r == qr) {
          a[root].Min += len;
          a[root].add += len;
          return;
      }
      pushdown(root, false);
      int mid = (l + r) / 2;
      if (mid >= qr) add(a[root].lc, l, mid, ql, qr, len);
      else if (mid + 1 <= ql) add(a[root].rc, mid + 1, r, ql, qr, len);
      else add(a[root].lc, l, mid, ql, mid, len), add(a[root].rc, mid + 1, r, mid + 1, qr, len);
  }
  void recalc(int root, int l, int r, int pos) {
      if (l == r) {
          a[root].Min = Treap.lcp(a[root].root, a[last].root);
          return;
      }
      pushdown(root, true);
      int mid = (l + r) / 2;
      if (mid >= pos) recalc(a[root].lc, l, mid, pos);
      else recalc(a[root].rc, mid + 1, r, pos);
      update(root);
  }
  void recalc(int pos) {
      access(root, 1, n, pos - 1);
      recalc(root, 1, n, pos);
  }
  void modify(int l, int r, int rt) {
      modify(root, 1, n, l, r, rt);
      if (l != r) add(root, 1, n, l + 1, r, Treap.length(rt));
      if (l != 1) recalc(l);
      if (r != n) recalc(r + 1);
  }
} ST;
char getopt() {
  char ch = getchar();
  while (ch != 'I' && ch != 'Q') ch = getchar();
  return ch;
}
int main() {
  int n, m; read(n), read(m);
  Treap.init(), ST.init(n);
  for (int i = 1; i <= m; i++) {
      if (getopt() == 'Q') {
          int l, r; read(l), read(r);
          writeln(ST.query(l, r));
      } else {
          int l, r; read(l), read(r);
          int tmp = Treap.load();
          ST.modify(l, r, tmp);
      }
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/82459587