HDU 3973 AC's String 字符串哈希
2015-07-26 20:02
183 查看
HDU 3973
通过哈希函数将一个字符串转化为一个整数,通过特定的方式可以使得这个哈希值几乎没有冲突(这就是关键之处,几乎没有视为没有= =!, 其实也可以考虑实现哈希冲突时的处理,只是这道题没必要而已),然后使用线段树维护修改后的哈希值。
因为输入的字符串只有26个,考虑使用一个大于等于26的素数p作为进制,然后将原串转化为一个p进制的数mod 2^63(也相当于自然溢出),然后这个数存入map中,然后使用线段树维护长串区间的哈希值,hash[l, r]表示将区间[l, r]的字符串转化为p进制数(哈希过程)的结果,那么对于当前区间[l, r]的两个子区间[l, m]与[m + 1, r]:
hash[l, r] = hash[l, m] + hash[m + 1, r] * (p ^ (m - l + 1))
使用线段树动态维护,查询区间的hash值,使用map查找,那么问题就解决了。
通过哈希函数将一个字符串转化为一个整数,通过特定的方式可以使得这个哈希值几乎没有冲突(这就是关键之处,几乎没有视为没有= =!, 其实也可以考虑实现哈希冲突时的处理,只是这道题没必要而已),然后使用线段树维护修改后的哈希值。
因为输入的字符串只有26个,考虑使用一个大于等于26的素数p作为进制,然后将原串转化为一个p进制的数mod 2^63(也相当于自然溢出),然后这个数存入map中,然后使用线段树维护长串区间的哈希值,hash[l, r]表示将区间[l, r]的字符串转化为p进制数(哈希过程)的结果,那么对于当前区间[l, r]的两个子区间[l, m]与[m + 1, r]:
hash[l, r] = hash[l, m] + hash[m + 1, r] * (p ^ (m - l + 1))
使用线段树动态维护,查询区间的hash值,使用map查找,那么问题就解决了。
//#pragma comment(linker, "/STACK:1677721600") #include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <ctime> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f #define inf (-((LL)1<<40)) #define lson k<<1, L, (L + R)>>1 #define rson k<<1|1, ((L + R)>>1) + 1, R #define mem0(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,-1,sizeof(a)) #define mem(a, b) memset(a, b, sizeof(a)) #define FIN freopen("in.txt", "r", stdin) #define FOUT freopen("out.txt", "w", stdout) #define rep(i, a, b) for(int i = a; i <= b; i ++) #define dec(i, a, b) for(int i = a; i >= b; i --) template<class T> T MAX(T a, T b) { return a > b ? a : b; } template<class T> T MIN(T a, T b) { return a < b ? a : b; } template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; } template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; } //typedef __int64 LL; typedef long long LL; const int MAXN = 100000 + 100; const int MAXM = 110000; const double eps = 1e-8; LL MOD = 1000000007; const LL P = 33; int t, n, m, cas = 0, l, r; LL mi[MAXN]; char str[2000001], ch; map<LL, int>mp; void init() { mi[0] = 1; rep (i, 1, MAXN - 1) { mi[i] = mi[i - 1] * P; } } int toNum(char ch) { return ch - 'a' + 1; } LL Hash() { LL ans = 0; int len = strlen(str); dec (i, len - 1, 0) { ans = ans * P + toNum(str[i]); } return ans; } struct SegTree { LL ma[MAXN << 2]; void update(int k, int L, int R, int p, int v) { if(L == R) { ma[k] = v; return ; } int mid = (L + R) >> 1; if(mid >= p) update(lson, p, v); else update(rson, p, v); ma[k] = ma[k << 1] + ma[k << 1 | 1] * mi[mid - L + 1]; } LL query(int k, int L, int R, int l, int r) { if(r < L || R < l) return 0; if(l <= L && R <= r) return ma[k]; LL le = query(lson, l, r), ri = query(rson, l, r); int mid = (L + R) >> 1; return le + ri * mi[max(mid - max(L, l) + 1, 0)]; } }st; int main() { // FIN; init(); cin >> t; while(t--) { mp.clear(); mem0(st.ma); scanf("%d%*c", &n); rep (i, 0, n - 1) { scanf("%s", str); mp[Hash()] = 1; } scanf("%s", str); int len = strlen(str); rep (i, 0, len - 1) { st.update(1, 1, len, i + 1, toNum(str[i])); } printf("Case #%d:\n", ++cas); scanf("%d%*c", &m); while(m --) { scanf("%c", &ch); if(ch == 'Q') { scanf("%d %d%*c", &l, &r); printf("%s\n", mp[st.query(1, 1, len, ++l, ++r)] ? "Yes" : "No"); } else { scanf("%d %c%*c", &l, &ch); st.update(1, 1, len, ++l, toNum(ch)); } } } return 0; }
相关文章推荐
- iostream
- sift是图像匹配的非常经典的算法
- DFS-POJ-1321-棋盘问题
- 【BMI指数计算器V2.0】项目实战
- GestureOverlayView(手势识别2)
- shape layer-list selector使用
- Watch The Movie(严格限制数量的二维费用背包)
- 在空白处填充程序3
- G - Balanced Lineup - poj3264(区间查询)
- LeetCode---(160)Intersection of Two Linked Lists判断两个链表是否相交
- 折半查找
- HDU-3714 Error Curves
- Java多线程的~~~Lock接口和ReentrantLock使用
- 数据结构:图 (总结)
- 折半查找
- vector 四
- Git使用教程(四)--远程仓库
- BFS-POJ-3278-Catch That Cow
- LeetCode(94) Binary Tree Inorder Traversal
- 三个同步与互斥问题之哲学家就餐