Loading

P3792 由乃与大母神原型和偶像崇拜 线段树 哈希

P3792 由乃与大母神原型和偶像崇拜 线段树 哈希

题意

给一个长度为\(n\)的序列\(a\),每次两个操作

  • 修改\(x\)位置为\(y\)
  • 查询区间\([l,r]\)是否可以重排为值域上连续的一段(如[1,3,4,2]是连续的一段,[1,4,4,2]不是连续的一段)

\[n,m\leq 500000 \\初始值域小于2.5\times10^7 \\ 修改y小于n \]

分析

比较容易想到的方法是用线段树维护区间最小值,最大值。

如果最大值减去最小值等于区间长度那么这一段有可能是连续的,下一步只需判断重复的情况

方法1:维护每个数左边第一个等于他的数,只需要查询区间最大值判断是否小于左端点即可

方法2:维护区间和,平方和,甚至立方和。。哈希判断是区间各种和是否等于应该的区间和即可

方法3:受题解启发,可以类似字符串哈希的方式进行进制哈希,哈希的底数选取一个大于值域的质数并取模一个质数

由于要的是连续的一段,因此需要的哈希值可以立刻求出,只需要线段树维护哈希值和最小值即可

代码

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;

ull readull(){
	ull x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar(); 
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f * x;
}
int readint(){
	int x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar(); 
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f * x;
}

const int maxn  = 5e5 + 5;
const int MOD = 1e9 + 7;
const int BASE = 2.5e7 + 7;

int n,m;
int a[maxn];

int ksm(int a,int b) {
	int ans = 1;
	int base = a;
	while(b){
		if(b & 1)
			ans = (ll) ans * base % MOD;
		base = (ll) base * base % MOD;
		b >>= 1;
	} 
	return ans;
}

struct Tree{
	int v;
	int h;
	Tree(){}
	Tree(int _v,int _h){
		v = _v;
		h = _h;
	}
};

Tree node[maxn << 2];

void push_up(int i){
	node[i].v = min(node[i << 1].v,node[i << 1|1].v);
	node[i].h = (node[i << 1].h + node[i << 1|1].h) % MOD;
}

void build(int i,int l,int r){
	if(l == r) {
		node[i].v = a[l];
		node[i].h = ksm(BASE,a[l]);
		return;
	}
	int mid = l + r >> 1;
	build(i << 1,l,mid);
	build(i << 1|1,mid + 1,r);
	push_up(i);	
}

void update(int i,int l,int r,int p,int v){
	if(l == r){
		node[i].v = v;
		node[i].h = ksm(BASE,v);
		return;
	}
	int mid = l + r >> 1;
	if(p <= mid) update(i << 1,l,mid,p,v);
	else update(i << 1|1,mid + 1,r,p,v);
	push_up(i);
}

Tree query(int i,int l,int r,int L,int R){
	if(l >= L && r <= R) return node[i];
	int mid = l + r >> 1;
	Tree res = Tree(1e9,0);
	if(L <= mid) res = query(i << 1,l,mid,L,R);
	if(R > mid) {
		Tree t = query(i << 1|1,mid + 1,r,L,R);
		res = Tree(min(res.v,t.v),(res.h + t.h) % MOD);
	}
	return res;
}	

int f[maxn];

int main(){
	n = readint();
	m = readint();
	for(int i = 1;i <= n;i++)
		a[i] = readint();
	build(1,1,n);
	f[1] = 1;
	for(int i = 2;i <= n;i++) 
		f[i] = ((ll)((ll)f[i - 1] * BASE + 1)) % MOD;
	while(m--){
		int op = readint();
		int l = readint();
		int r = readint();	
		if(op == 1) update(1,1,n,l,r);
		else{
			Tree tmp = query(1,1,n,l,r);
			if(tmp.h == (ll)f[r- l + 1] * ksm(BASE,tmp.v) % MOD) puts("damushen");
			else puts("yuanxing");
		}
	} 
}
posted @ 2020-11-05 16:47  MQFLLY  阅读(84)  评论(0编辑  收藏  举报