zoukankan      html  css  js  c++  java
  • P3792 由乃与大母神原型和偶像崇拜 线段树 哈希

    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");
    		}
    	} 
    }
    
  • 相关阅读:
    jquery 功能优化
    MySQL Group Replication集群部署,基于官方文档
    django-filter跨表过滤,区间过滤
    xadmin默认显示用户名,密码,确认密码,添加字段
    函数的装饰器修复技术(@wraps)
    redis的特点总结-安装及基本命令的使用
    前后台分离时-后台处理跨域
    djangorestframework-jwt模块
    drf模块请求组件,响应组件,异常组件
    html 中画半圆的方法
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13932568.html
Copyright © 2011-2022 走看看