HDU-4339 Query 线段树+多项式插值hash
这题主要是要将两个串的比较进行优化,不能够每次都从起始位置进行匹配。
这里用到了线段树进行优化,将每段区间的hash值进行更新和维护,通过找某一点的有连续段最长相同串即可。
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #define MOD 100000003 #define T 29LL using namespace std; typedef unsigned int Int64; // 这里建立棵线段树记录某一短区间的hash值 char str[2][1000005]; Int64 _pow[1000005]; int ans; struct Node { int l, r;//, key1, key2; Int64 rkey1, rkey2; }s[4000005]; void pre() { _pow[0] = 1; for (int i = 1; i <= 1000000; ++i) { _pow[i] = _pow[i-1] * T; } } void push_up(int p) { s[p].rkey1 = s[p<<1].rkey1 + s[p<<1|1].rkey1*_pow[s[p<<1].r-s[p<<1].l+1]; s[p].rkey2 = s[p<<1].rkey2 + s[p<<1|1].rkey2*_pow[s[p<<1].r-s[p<<1].l+1]; } void build(int p, int l, int r) { s[p].l = l, s[p].r = r; if (l != r) { int mid = (l + r) >> 1; build(p<<1, l, mid); build(p<<1|1, mid+1, r); push_up(p); } else { s[p].rkey1 = str[0][r]; s[p].rkey2 = str[1][r]; } } void modify(int p, int kind, int pos, char val) { if (s[p].l == s[p].r) { if (kind == 1) { s[p].rkey1 = val - 'a'; } else { s[p].rkey2 = val - 'a'; } } else { int mid = (s[p].l + s[p].r) >> 1; if (pos <= mid) { modify(p<<1, kind, pos, val); } else { modify(p<<1|1, kind, pos, val); } push_up(p); } } int find(int p) { if (s[p].rkey1 == s[p].rkey2) { return s[p].r - s[p].l + 1; } else if (s[p].l != s[p].r){ int ret = find(p<<1); if (ret == s[p<<1].r - s[p<<1].l + 1) { ret += find(p<<1|1); } return ret; } else { return 0; } } int query(int p, int x) { if (s[p].l == s[p].r) { if (s[p].rkey1 == s[p].rkey2) { return 1; } else { return 0; } } else { int mid = (s[p].l + s[p].r) >> 1, ret = 0; if (x <= mid) { ret = query(p<<1, x); if (ret == s[p<<1].r-x+1) { // 左边已经连续且饱满 ret += find(p<<1|1); } } else { ret = query(p<<1|1, x); } return ret; } } int main() { int M, Q, len1, len2, cnt, op, ca = 0, x, y; char t[5]; pre(); scanf("%d", &M); while (M--) { scanf("%s %s", str[0], str[1]); len1 = strlen(str[0]); len2 = strlen(str[1]); cnt = min(len1, len2); for (int i = 0; i < cnt; ++i) { str[0][i] -= 'a', str[1][i] -= 'a'; } // 进行脱字母化,这样能够使T的取值变小 build(1, 0, cnt-1); scanf("%d", &Q); printf("Case %d:\n", ++ca); while (Q--) { scanf("%d", &op); if (op == 1) { scanf("%d %d %s", &x, &y, t); if (y >= cnt) { continue; } modify(1, x, y, t[0]); } else { scanf("%d", &x); if (x >= cnt) { puts("0"); continue; } printf("%d\n", query(1, x)); } } } return 0; }