1. 程式人生 > >BZOJ 1014 火星人 | 平衡樹維護哈希

BZOJ 1014 火星人 | 平衡樹維護哈希

cst pos urn chan getch line signed 維護 平衡樹

BZOJ 1014 火星人

題意

有一個字符串,三中操作:在某位置後面插入一個字符、修改某位置的字符、詢問兩個後綴的最長公共前綴。

題解

看到網上的dalao們都說這道題是平衡樹,我就很懵x……平衡樹維護什麽啊?
最後發現某個節點維護的是它所代表的區間的哈希值——顯然這個哈希值可以從左右子樹的哈希值和這個節點上的字符算出來。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define space putchar(' ')
#define enter putchar('
\n') using namespace std; typedef unsigned long long ll; template <class T> void read(T &x){ char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0'
&& c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x){ if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 100005, B = 29; int n, m; int idx, root, fa[N], ls[N], rs[N], val[N], sze[N]; ll hsh[N], pw[N]; char
s[N]; #define which(x) (ls[fa[(x)]] == (x)) void upt(int u){ sze[u] = sze[ls[u]] + sze[rs[u]] + 1; hsh[u] = hsh[ls[u]] + val[u] * pw[sze[ls[u]]] + hsh[rs[u]] * pw[sze[ls[u]] + 1]; } void rotate(int u){ int v = fa[u], w = fa[v], b = which(u) ? rs[u] : ls[u]; if(w) which(v) ? ls[w] = u : rs[w] = u; which(u) ? (ls[v] = b, rs[u] = v) : (rs[v] = b, ls[u] = v); fa[u] = w, fa[v] = u; if(b) fa[b] = v; upt(v), upt(u); } void splay(int u, int tar){ while(fa[u] != tar){ if(fa[fa[u]] != tar){ if(which(u) == which(fa[u])) rotate(fa[u]); else rotate(u); } rotate(u); } if(!tar) root = u; } int build(int l, int r, int pre){ if(l > r) return 0; int u = ++idx, mid = (l + r) >> 1; val[u] = s[mid] - 'a' + 1, fa[u] = pre; ls[u] = build(l, mid - 1, u); rs[u] = build(mid + 1, r, u); upt(u); return u; } int find(int x){ int u = root; while(sze[ls[u]] != x) if(x <= sze[ls[u]] - 1) u = ls[u]; else x -= sze[ls[u]] + 1, u = rs[u]; return u; } void insert(int pos, int x){ int u = find(pos), v = find(pos + 1); splay(u, 0), splay(v, u); ls[v] = ++idx, fa[idx] = v, val[idx] = x, sze[idx] = 1; splay(idx, 0); } void change(int pos, int x){ int u = find(pos); val[u] = x; splay(u, 0); } ll gethsh(int pos, int len){ int u = find(pos - 1), v = find(pos + len); splay(u, 0), splay(v, u); return hsh[ls[v]]; } int query(int a, int b){ int l = 0, r = sze[root] - max(a, b) - 1, mid; while(l < r){ mid = (l + r + 1) >> 1; if(gethsh(a, mid) == gethsh(b, mid)) l = mid; else r = mid - 1; } return l; } int main(){ scanf("%s", s + 1); n = strlen(s + 1); pw[0] = 1; for(int i = 1; i < N; i++) pw[i] = pw[i - 1] * B; root = build(0, n + 1, 0); read(m); while(m--){ char op[2]; scanf("%s", op); if(op[0] == 'Q'){ int a, b; read(a), read(b); write(query(a, b)), enter; } else if(op[0] == 'I'){ int pos; scanf("%d%s", &pos, op); insert(pos, op[0] - 'a' + 1); } else if(op[0] == 'R'){ int pos; scanf("%d%s", &pos, op); change(pos, op[0] - 'a' + 1); } } return 0; }

BZOJ 1014 火星人 | 平衡樹維護哈希