HDU 5790 Prefix(Hash + 主席树)
题目链接 Prefix
题意 给定一个字符串序列,求第$l$个字符串到第$r$个字符串之间有多少个不同的前缀
强制在线
考虑$Hash$
首先把所有前缀都$hash$出来,按顺序组成一个长度不超过$10^{5}$的序列。
然后放入主席树,问题转化为查询区间内不同数字的个数。
查询的时候找到的起始字符串的开头和终止字符串的结尾就可以了。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef unsigned long long ULL; const int N = 1e5 + 10; const int M = 4e6 + 10; ULL a[N], b[N], val[M], g[200]; int c[N], d[N], T[M], lson[M], rson[M], nxt[N], idx, len, n, tot, nn, Z; char st[N]; int build(int l, int r){ int rt = tot++; val[rt] = 0; int m = (l + r) >> 1; if(l != r){ lson[rt] = build(l, m); rson[rt] = build(m + 1, r); } return rt; } int update(int rt, int pos, int v){ int newrt = tot++, tmp = newrt; int l = 1, r = n; val[newrt] = val[rt] + v; while(l < r) { int m = (l + r) >> 1; if(pos <= m) { lson[newrt] = tot++; rson[newrt] = rson[rt]; newrt = lson[newrt]; rt = lson[rt]; r = m; } else { rson[newrt] = tot++; lson[newrt] = lson[rt]; newrt = rson[newrt]; rt = rson[rt]; l = m + 1; } val[newrt] = val[rt] + v; } return tmp; } int query(int rt, int pos){ int ret = 0; int l = 1, r = n; while(pos > l){ int m = (l + r) >> 1; if (pos <= m){ ret += val[rson[rt]]; rt = lson[rt]; r = m; } else{ l = m + 1; rt = rson[rt]; } } return ret + val[rt]; } int ask(int l, int r){ return query(T[r], l); } void init(){ tot = 0; memset(nxt, -1, sizeof(nxt)); rep(i, 1, n) b[i - 1] = a[i]; sort(b, b + n); int cnt = unique(b, b + n) - b; T[0] = build(1, n); rep(i, 1, n){ int id = lower_bound(b, b + cnt, a[i]) - b; if(nxt[id] == -1) T[i] = update(T[i - 1], i, 1); else{ int t = update(T[i - 1], nxt[id], -1); T[i] = update(t, i, 1); } nxt[id] = i; } } inline ULL get(char ch){ return g[(int)ch - 97]; } int main(){ srand(time(NULL)); rep(i, 0, 100){ int yy = rand() % 3 + 1; g[i] = 1; rep(j, 1, yy) g[i] *= rand(); } while (~scanf("%d", &nn)){ Z = 0; n = 0; rep(i, 1, nn){ scanf("%s", st); len = strlen(st); ULL haha = 0LL; rep(j, 0, len - 1){ ++n; haha = haha * 233LL + 6843 * get(st[j]); a[n] = haha; } c[i] = d[i - 1] + 1; d[i] = n; } init(); int q; scanf("%d", &q); Z = 0; while (q--){ int x, y; scanf("%d%d", &x, &y); int ll = (Z + x) % nn + 1; int rr = (Z + y) % nn + 1; if (ll > rr) swap(ll, rr); printf("%d\n", Z = ask(c[ll], d[rr])); } } return 0; }