fzu 2045 \ hdu 3973 AC's String(线段树+RK)

题意:给出10000个模式串和一个长度为100000的匹配串,有两种操作:

1.查询匹配串的子串[L,R]是否存在于模式串中

2.修改匹配串某个位置的字符

解法:由于RK函数满足区间加法啊,因此可以用线段树动态维护和查询某个子串的hash值,得到子串的hash值,剩下的就是普通的rk了。

将所有模式串的hash值放入map中,对于hash值相同的模式串使用链表串联起来,当获取某个子串的hash值时 ,首先在map中查找是否存在,若存在和此hash值链表上的模式串一一比较。


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.TreeMap;

public class FZU2045ac {
	long mod = 100000007;
	int maxn = 100010;

	long pow(long x, int p) {
		long ans = 1;
		while (p > 0) {
			if ((p & 1) == 1)
				ans = (ans * x) % mod;
			p >>= 1;
			x = (x * x) % mod;
		}
		return ans;
	}

	class SegTree {
		class node {
			int left, right;
			long hash;
			node(int l, int r) {
				left = l;
				right = r;
			}
			int length() {
				return right - left + 1;
			}
			int mid() {
				return (left + right) >> 1;
			}
		}

		node tree[] = new node[maxn << 2];
		void init(int idx, int l, int r, int arr[]) {
			tree[idx] = new node(l, r);
			if (l == r) {
				tree[idx].hash = arr[r];
				return;
			}
			int m = tree[idx].mid();
			init(idx << 1, l, m, arr);
			init(idx << 1 | 1, m + 1,r, arr);
			pushup(idx);
		}

		void pushup(int idx) {
			if (tree[idx].left == tree[idx].right)
				return;
			tree[idx].hash = (tree[idx<<1].hash
					* pow(26, tree[idx<<1|1].length())+tree[idx<< 1|1].hash)
					% mod;
		}
		long query(int idx, int left, int right) {
			if (tree[idx].left==left&&tree[idx].right== right)
				return tree[idx].hash;
			int m = tree[idx].mid();
			if (right<=m)
				return query(idx << 1, left, right);
			if (left>m)
				return query(idx << 1 | 1, left, right);
			long x = query(idx << 1, left, m);
			long y = query(idx << 1 | 1, m + 1, right);
			return (x*pow(26,right-m)+y) % mod;
		}

		void update(int idx, int pos, long val) {
			if (tree[idx].left == pos && tree[idx].right == pos) {
				tree[idx].hash = val;
				return;
			}
			int m = tree[idx].mid();
			if (m >= pos)
				update(idx<<1,pos,val);
			else
				update(idx<<1|1,pos,val);
			pushup(idx);
		}
	}

	String ss[] = new String[10010];
	int nxt[] = new int[10010], pre[] = new int[10010];
	TreeMap<Long, Integer> mp = new TreeMap<Long, Integer>();

	void build() throws IOException {
		int n = nextInt();
		Arrays.fill(nxt, -1);
		Arrays.fill(pre, -1);
		mp.clear();
		for (int i = 1; i <= n; i++) {
			ss[i] = next();
			int len = ss[i].length();
			long hash = 0;
			for (int j = 0; j < len; j++)
				hash = (hash * 26 + (ss[i].charAt(j) - 'a')) % mod;
			if (mp.containsKey(hash)) {
				int temp = mp.get(hash);
				pre[i] = temp;
				nxt[temp] = i;
			}
			mp.put(hash, i);
		}
	}

	boolean test(int l, int r) {
		long hash = st.query(1, l, r);
		if (!mp.containsKey(hash))
			return false;
		int p = mp.get(hash);
		while (pre[p] != -1)
			p = pre[p];
		while (p != -1) {	
			if (r - l + 1 == ss[p].length()){
				boolean flag = true;
				for (int i = 0; i < r - l + 1; i++)
					if (ss[p].charAt(i) - 'a' != arr[l + i]) {
						flag = false;
						break;
					}
			if (flag)
				return true;
			}
			p = nxt[p];
		}
		return false;
	}

	int arr[] = new int[maxn];
	SegTree st = new SegTree();

	void run() throws IOException {
		int cas = nextInt();
		for (int c = 1; c <= cas; c++) {
			System.out.println("Case #"+c+":");
			build();
			String s = next();
			int cnt = s.length();
			for (int i = 1; i <= cnt; i++)
				arr[i] = s.charAt(i - 1) - 'a';
			st.init(1, 1, cnt, arr);
			int m = nextInt();
			while (m-- > 0) {
				String op = next();
				if (op.charAt(0) == 'Q')
					if (test(nextInt()+1, nextInt()+1))
						System.out.println("Yes");
					else
						System.out.println("No");
				else {
					int p = nextInt()+1;
					int val = next().charAt(0) - 'a';
					st.update(1, p, val);
					arr[p] = val;
				}
			}
		}
	}
	StreamTokenizer in = new StreamTokenizer(new BufferedReader(
			new InputStreamReader(System.in)));
	int nextInt() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}
	String next() throws IOException {
		in.nextToken();
		return in.sval;
	}
	public static void main(String[] args) throws IOException {
		new FZU2045ac().run();
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值