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");
                }
            }
        }
    }

    

}
posted @ 2020-09-26 00:15  ccsu_zhaobo  阅读(116)  评论(0编辑  收藏  举报