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

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

    题意: 给你n个数, q次询问, 每次询问 有

    • 1 x, y 表示将x的值改成y
    • 2 l,r 询问区间l 到r 从小到达排序后是否连续。

    题解:

    如果这题不带修改,很多人都会想到,直接用主席树维护一个最大值最小值, 然后查询区间不同数的个数, 如果不同数的个数等于maxn - minn + 1 那么这个区间一定合法。

    主席树比较麻烦?

    那就用线段树维护一个最大一个最小值, 一个这个数第一出现的位置的最小值。

    如果 maxn - minn == r - l 且 min_pos > r那么一定是个合法的区间。

    但是这题带修改怎么办呢?

    有一种非常的巧妙的想法, 类似有hash

    可以线段树维护一个区间和, 区间异或和, 区间乘积, 区间最大值, 区间最小值。

    如果maxn - minn == r - l

    在判断区间和, 区间异或和, 区间乘积是否都和连续的值相等, 如果相等这个区间大概率符合。

    维护的东西越多, 错误率就越低。

    但是这题卡空间, 因为修改操作都是小于n的所有 没用修改的直接用上面的线段树方法查询答案, 之前修改过了

    在用这个hash的方法解决这个问题。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 5e5 + 7;
    const ll mod = 1e9 + 7;
    
    struct segment {
        int maxn, minn;
        long long sum, o, mul;
        int min_pos;
        bool ok;
    
        segment operator +(const segment &n)  {
            segment ans;
            ans.maxn = max(this->maxn, n.maxn);
            ans.minn = min(this->minn, n.minn);
            ans.mul = (this->mul % mod * n.mul % mod) % mod;
            ans.sum = this->sum + n.sum;
            ans.o = this->o ^ n.o;
            ans.ok = this->ok | n.ok;
            ans.min_pos = min(this->min_pos, n.min_pos);
            return ans;
        }
    
    }tree[4 * N];
    
    #define m  (l + r) / 2
    #define lson  2 * node
    #define rson  2 * node + 1
    int a[N];
    
    void build(int l, int r, int node) {
        if (l == r) {
            tree[node].maxn = a[l];
            tree[node].minn = a[l];
            tree[node].sum = tree[node].o = tree[node].mul = a[l]; 
            return;
        }
    
        build(l, m, lson);
        build(m + 1, r, rson);
        tree[node] = tree[lson] + tree[rson];
    }
    
    segment query(int ql, int qr, int l, int r, int node) {
        if (ql <= l && qr >= r) {
            return tree[node];
        }
        segment ans;
        ans.maxn = 0, ans.minn = INT_MAX, ans.mul = 1, ans.o = 0, ans.sum = 0;
        ans.min_pos = 1000000000,  ans.ok = 0;
    
        if (ql <= m) {
            ans =ans + query(ql, qr, l, m, lson);
        } 
        if (qr > m) {
            ans =ans + query(ql, qr, m + 1, r, rson);
        }
        return ans;
    }
    
    void update(int v, int pos, int l, int r, int node) {
        if (l == r) {
            tree[node].min_pos = v;
            tree[node].ok = false;
            return;
        }
    
        if (pos <= m) update(v, pos, l, m, lson);
        else update(v, pos ,m + 1, r, rson);
        tree[node].min_pos = min(tree[lson].min_pos, tree[rson].min_pos);
    }
    
    void up(int v, int pos, int l, int r, int node) {
        tree[node].ok = true;
        if (l == r) {
            tree[node].maxn = v;
            tree[node].minn = v;
            tree[node].sum = tree[node].o = tree[node].mul = v;
            return; 
        }
    
        if (pos <= m) up(v, pos, l, m, lson);
        else up(v, pos, m + 1, r, rson);
        tree[node] = tree[lson] + tree[rson];
    
    }
    
    int vis[25000007];
    
    long long sum[2 * N], cnt[2 * N], mul[2 * N];
    
    ll ksm(ll x, ll y) {
        x = x % mod;
        ll base = 1;
        while (y) {
            if (y & 1) {
                base = base * x;
                base %= mod;
            }
            x = x * x % mod;
            y = y / 2;
        }
        return base;
    }
    inline int read(){
        int x=0,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 x*f;
    }
    
    
    int main() {
    
        
        int n, q;
        n = read(), q = read();
        for (int i = 1; i <= n; i++) {
            a[i] = read();
        }
        mul[0] = 1;
        for (int i = 1; i < 2 * N; i++) {
            sum[i] = sum[i - 1] + i;
            cnt[i] = cnt[i - 1] ^ i;
            mul[i] = (mul[i - 1] * i) % mod;
        }
        build(1, n, 1);
    
        for (int i = n; i; i--) {
            if (vis[a[i]]) {
               update(vis[a[i]], i, 1, n, 1); 
            } else {
                update(n + 1, i, 1, n, 1);
            }
            
            vis[a[i]] = i;
        }
      
        while (q--) {
            int op, l, r;
           // scanf("%d %d %d", &op, &l, &r);
           op = read(), l = read(), r = read();
            if (op == 1) {
                up(r, l, 1, n, 1);
            } else {
                segment ans = query(l, r, 1, n, 1);
                if (ans.ok) {
                    if (ans.maxn - ans.minn == r - l) {
                        r = ans.maxn, l = ans.minn;
                        ll cn = sum[r] - sum[l - 1];
                        ll cn1 = cnt[r] ^ cnt[l - 1];
                        ll inv = ksm(mul[l - 1], 1e9 + 5);
                        ll cn2 = (mul[r] % mod * inv % mod) % mod;
    
                        if (ans.mul == cn2 && ans.sum == cn && ans.o == cn1) {
                            puts("damushen");
                        } else {
                            puts("yuanxing");
                        }
                    } else {
                        puts("yuanxing");
                    }
    
                } else {
                    if (ans.maxn - ans.minn == r - l && ans.min_pos > r ) {
                        puts("damushen");
                    } else {
                        puts("yuanxing");
                    }
                }
            }
        }
    
        
    
    }
    
  • 相关阅读:
    JDK代理(必须代理类要实现一个接口)
    Spring整合jdbc
    Python 之正则匹配
    Spark ML 之 LR逻辑回归实现排序
    Spark 之 读取配置连接Mysql和上传到HDFS
    Spark ML 之 推荐算法项目(上)
    Spark ML 之 推荐算法项目(下)
    Spark ML 之 ALS内存溢出的解决办法
    Spark ML 之 基于协同过滤的召回算法
    Spark ML 特征处理类之 VectorAssembler 向量装配转换器/VectorIndexer
  • 原文地址:https://www.cnblogs.com/BOZHAO/p/13733235.html
Copyright © 2011-2022 走看看