HDU 3973 (哈希+线段树)

题目链接:点击打开链接

题意:给出一个原串和n个询问串,然后m个操作,询问分两种:

1:把x位置的字母改变;2:询问[x,y]之间的字符串是不是等于某个询问串。

先把每一个询问串的哈希值存到map里面,然后用线段树维护每一个区间的字符串的哈希

值,如果需要的串包含左右两个区间,就把右边区间求出的哈希值进左边区间的长度位。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#define maxn 111111
#define pl c<<1
#define pr (c<<1)|1
#define lson tree[c].l,tree[c].mid,pl
#define rson tree[c].mid+1,tree[c].r,pr
typedef unsigned long long ull;
#define pow Pow
#define hash Hash
#define seed 131

struct node {
	int l, r, mid;
	ull num;
} tree[maxn<<4];
map <ull, int> mp;
int m, n, q;
char a[2111111];
ull pow[2111111];

ull f (char a) {
	return a-'a'+1;
}

void push_up (int c) {
	if (tree[c].l == tree[c].r)
		return ;
	tree[c].num = tree[pl].num + tree[pr].num * pow[tree[pl].r-tree[pl].l+1];
	return ;
}

void build_tree (int l, int r, int c) {
	tree[c].l = l, tree[c].r = r, tree[c].mid = (l+r)/2;
	if (l == r) {
		tree[c].num = f (a[l]);
		return ;
	}
	build_tree (lson);
	build_tree (rson);
	push_up (c);
}

void update (int l, int r, int c, int pos, int num) {
	if (l == r) {
		tree[c].num = num;
		return ;
	}
	if (tree[c].mid >= pos) 
		update (lson, pos, num);
	else 
		update (rson, pos, num);
	push_up (c);
}

ull query (int l, int r, int c, int x, int y) {
	if (x > y)
		return 0;
	if (l == x && y == r) {
		return tree[c].num;
	}
	if (tree[c].mid >= x) {
		return query (lson, x, tree[c].mid) + query (rson, tree[c].mid+1, y) * 
		pow[tree[pl].r-x+1];
	}
	else {
		return query (rson, x, y);
	}
}

void debug (int c) {
	cout << tree[c].l << " " << tree[c].r << " " << tree[c].num << endl;
	if (tree[c].l == tree[c].r)
		return ;
	debug (pl);
	debug (pr);
}

int main () {
	pow[0] = 1;
	for (int i = 1; i <= 2000000; i++) {
		pow[i] = pow[i-1]*seed;
	}
	int t, kase = 0;
	scanf ("%d", &t);
	while (t--) {
		printf ("Case #%d:\n", ++kase);
		mp.clear ();
		scanf ("%d", &m);
		for (int i = 0; i < m; i++) {
			ull hash = 0;
			scanf ("%s", a);
			n = strlen (a);
			for (int i = n-1; i >= 0; i--) {
				hash = hash*seed+f(a[i]);
			}
			mp[hash] = 1;
		}
		scanf ("%s", a+1); a[0] = '0'; 
		n = strlen (a); n--; 
		build_tree (1, n, 1);
		//debug (1);

		scanf ("%d", &q);
		char op[22]; int l, r;
		char change[22];
		while (q--) {
			scanf ("%s", op);
			if (op[0] == 'Q') {
				scanf ("%d%d", &l, &r);
				l++, r++;
				ull ans_l = query (1, n, 1, l, n);
				ull ans_r = query (1, n, 1, r+1, n);
				ull ans = ans_l - ans_r*pow[r-l+1];
				if (mp.count (ans)) {
					printf ("Yes\n");
				}
				else 
					printf ("No\n");
			}
			else if (op[0] == 'C') {
				scanf ("%d%s", &l, change);
				l++;
				update (1, n, 1, l, f (change[0]));
			}
		}
	}
	return 0;
}
/*
1
5
z
zz
zzz
cd
fuck
asdfghjkl
11
C 5 u
C 6 c
Q 4 7
C 4 f
Q 4 7
C 1 z
Q 0 1
Q 1 1
C 2 z
Q 0 2
Q 1 2
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值