P5278题解

维护是否等差:

  1. 最大减最小是否等于公差乘长度

  2. 差的公因数是否是公差

  3. 没有相同的数

维护信息 :

  1. $gcd$ (差的最大公因数)

  2. $maxi$, $mini$ (最大值,最小值)

  3. $lnum$, $rnum$ (最左,右边的数)

  4. $maxpre$ (前驱的最大值(下标))

维护前驱

不妨设要把 $k$ 改为 $x$ , $k$ 原本是 $y$

  1. 上一个是 $x$ 的数的 $last$ 记为 $k$

  2. 下一个是 $x$ 的数的 $pre$ 记为 $k$

  3. 原来上一个是 $y$ 的数与下一个是 $y$ 的数连接,即前面的 $last$ 为后面,后面的 $pre$ 为前面。若哪个不存在,记为 0。

  • 若1,2条件若本来不存在,不考虑。

    $pre$ 为前驱,$last$ 为后继,再用 $set$ , $map$ 维护


#include <map>
#include <set>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef set<long long>::iterator si;

const int maxn = 4 * 1e5 + 10;
struct node {
    long long gcd, maxi, mini, lnum, rnum, max_pre;
} t[maxn << 2];
map <long long, int> mp;
set <long long> s[maxn];
long long n, m, a[maxn], pre[maxn], last[maxn];

int GCD (int x, int y) {
    return y == 0 ? x : GCD (y, x % y);
}

node father (node p, node q) {
    node f;
    f.max_pre = max (p.max_pre, q.max_pre);
    f.gcd = GCD (p.gcd, GCD (q.gcd, abs (q.lnum - p.rnum))); 
    f.maxi = max (p.maxi, q.maxi);
    f.mini = min (p.mini, q.mini);
    f.lnum = p.lnum; f.rnum = q.rnum;
    return f;
}

void build (int l, int r, int p) {
    if (l == r) {
        t[p].gcd = 0;
        t[p].max_pre = pre[l];
        t[p].maxi = t[p].mini = t[p].lnum = t[p].rnum = a[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build (l, mid, p << 1);
    build (mid + 1, r, p << 1 | 1);
    t[p] = father (t[p << 1], t[p << 1 | 1]);
}

void update (int p, int l, int r, int x, int v, int k) {
    if (r < x || l > x) return ;
    if (l == x && r == x) {
        t[p].max_pre = k;
        t[p].maxi = t[p].mini = t[p].lnum = t[p].rnum = v;
        return ;
    }
    int mid = (l + r) >> 1;
    if (x <= mid) update (p << 1, l, mid, x, v, k);
    else update (p << 1 | 1, mid + 1, r, x, v, k);
    t[p] = father (t[p << 1], t[p << 1 | 1]);
}

node query (int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
        return t[p];
    }
    int mid = (l + r) >> 1;
    if (y <= mid) return query (p << 1, l, mid, x, y);
    if (x > mid) return query (p << 1 | 1, mid + 1, r, x, y);
    return father (query (p << 1, l, mid, x, y), query (p << 1 | 1, mid + 1, r, x, y));
}

int main() {
    int tmp = 0, res = 0;
    scanf ("%lld%lld", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf ("%lld", &a[i]);
        if (mp.find(a[i]) == mp.end()) mp[a[i]] = ++ tmp, s[tmp].insert(i);
        else {
            int x = mp[a[i]]; int y = *--s[x].end();
            pre[i] = y; last[y] = i;
            s[x].insert(i);
        }
    }
    build (1, n, 1); 
    for (int i = 1; i <= m; ++i) {
        int op; cin >> op;
        if (op == 1) {
            long long x, y; scanf ("%lld%lld", &x, &y); 
            x ^= res; y ^= res;
            last[pre[x]] = last[x];
            pre[last[x]] = pre[x];
            int z = a[last[x]];
            update (1, 1, n, last[x], z, pre[x]);
            s[mp[a[x]]].erase(x);
            if (mp.find(y) == mp.end()){
                mp[y] = ++tmp, s[tmp].insert(i);
                pre[x] = last[x] = 0;
            } else {
                z = mp[y];
                si it = s[z].lower_bound(x);
                if (it == s[z].begin()){
                    pre[x] = 0; last[x] = *it;
                    pre[*it] = x;
                    update (1, 1, n, *it, a[*it], x);
                } else if (it == s[z].end()){
                    -- it;
                    pre[x] = *it; last[x] = 0;
                    last[*it] = x;
                } else {
                    si it1 = -- it; ++ it;
                    pre[x] = *it1; last[x] = *it;
                    last[*it1] = x; pre[*it] = x;
                    update (1, 1, n, *it, a[*it], x);
                }
            }
            a[x] = y;
            update (1, 1, n, x, y, pre[x]);
        } else {
            long long k, l, r;
            scanf ("%lld%lld%lld", &l, &r, &k);

            l ^= res; r ^= res; k ^= res;if (r < l) swap (l, r);
            node cnt = query (1, 1, n, l, r);
            if ((cnt.maxi - cnt.mini == k * (r - l)) && (cnt.gcd == k || !cnt.gcd) && (cnt.max_pre < l || !k)) res ++, printf ("Yes\n");
            else printf ("No\n");
        }
    }
    return 0;
}
posted @ 2021-05-15 19:44  wangzhongyuan  阅读(14)  评论(0编辑  收藏  举报  来源