P3792 由乃与大母神原型和偶像崇拜 线段树 哈希
题意
给一个长度为(n)的序列(a),每次两个操作
- 修改(x)位置为(y)
- 查询区间([l,r])是否可以重排为值域上连续的一段(如[1,3,4,2]是连续的一段,[1,4,4,2]不是连续的一段)
[n,mleq 500000
\初始值域小于2.5 imes10^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");
}
}
}