P3792 由乃与大母神原型和偶像崇拜

随机赋权哈希,算是板子题?

主要是想记录随机赋权 \(\text{hash}\) 这个 \(\text{trick}\)

显然,我们可以通过找到 \([l,r]\) 中的最小值 \(\text{min}\),从而确定,这连续的一段权值是 \([\text{min},\text{min}+r-l]\)

我们考虑如何去判断。

显然有一个简单的想法,就是对于 \([1,2.5\times 10^7]\) 中的每一个数,随机赋一个哈希权值 \(\text{val}_i\),然后维护一个 \(\text{sum}_i\) 表示 \(\text{sum}_i=\sum_{j=1}^{i} \text{val}_j\)

然后我们考虑维护每一个区间的 \(\sum \text{val}_i,i\in[l,r]\)

由于存在修改,考虑线段树维护这一过程,包括上面的区间最小值。

显然,我们最后只需要判断,\(\text{sum}_{\text{min}+r-l}-sum_{\text{min}-1}\) 是否与 \(\sum \text{val}_i,i\in[l,r]\) 相等即可。

由于是赋权,就会导致重复的概率极小,即使存在,你也可以通过选一个次数 \(k\)\(\text{sum}_i=\sum_{j=1}^{i} \text{val}_j^k\) 来减少错误的概率。

反正就是乱搞就能过。

#include <bits/stdc++.h>
using namespace std;
#define maxn 500005
#define maxe (int)(2.5e7)
int n, m;
int a[maxn], val[maxe + 5];
long long sum[maxe + 5];
struct segmentree
{
	int l, r;
	long long data;
	int minn; 
}tree[maxn << 2];
void update(int p)
{
	tree[p].data = tree[p << 1].data + tree[p << 1 | 1].data;
	tree[p].minn = min(tree[p << 1].minn, tree[p << 1 | 1].minn);
}
void build(int p, int l, int r)
{
	tree[p].l = l, tree[p].r = r;
	if(l == r) return tree[p].data = val[a[l]], tree[p].minn = a[l], void(0);
	int mid = (l + r) >> 1;
	build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
	update(p);
}
void change(int p, int x, int y)
{
	if(tree[p].l > x || tree[p].r < x) return;
	if(tree[p].l == tree[p].r) return tree[p].data = val[y], tree[p].minn = y, void(0);
	change(p << 1, x, y), change(p << 1 | 1, x, y);
	update(p);
}
pair<long long, int> query(int p, int l, int r)
{
	if(tree[p].l > r || tree[p].r < l) return make_pair(0, INT_MAX);
	if(tree[p].l >= l && tree[p].r <= r) return make_pair(tree[p].data, tree[p].minn);
	pair<long long, int> now1 = query(p << 1, l, r), now2 = query(p << 1 | 1, l, r);
	return make_pair(now1.first + now2.first, min(now1.second, now2.second));
}
int main()
{
	srand(time(NULL));
	for (int i = 1; i <= maxe; ++i) val[i] = rand() % (long long)(1e11), sum[i] = sum[i - 1] + val[i];
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	build(1, 1, n);
	while(m--)
	{
		int op, x, y;
		scanf("%d %d %d", &op, &x, &y);
		if(op == 1) change(1, x, y);
		else
		{
			pair<long long, int> ans = query(1, x, y);
			if(ans.second + (y - x) <= maxe && sum[ans.second + y - x] - sum[ans.second - 1] == ans.first) puts("damushen");
			else puts("yuanxing");
		}
	}
	return 0;
}
posted @ 2024-03-22 23:03  Saltyfish6  阅读(45)  评论(1编辑  收藏  举报
Document