CodeForces

n <= 5e5

两种操作:
1.询问 L ,R 能否通过修改一个数使得区间gcd为x

2. 修改某点的大小

首先联想到可以用线段树维护区间性质,单点修改。

如果判断1?

如果区间中所有数都是x的倍数,那么只需修改任意一个数变为x就可以。

如果区间中大于一个数不是x的倍数,由于仅仅能修改一次,所以肯定是false

剩下的情况就都可以了

注意线段树细节

struct Tree {
    int l, r, val , gcd;
};

Tree node[maxn * 4];
int a[maxn];


void Pushup(int i) {
    node[i].gcd = gcd(node[i << 1].gcd, node[i << 1 | 1].gcd);
}

void Build(int i, int l, int r) {
    node[i].l = l;
    node[i].r = r;
    if (l == r) {
        node[i].gcd = a[l];
        return;
    }
    int mid = l + r >> 1;
    Build(i << 1, l, mid);
    Build(i << 1 | 1, mid + 1, r);
    Pushup(i);
}


void update(int i, int l, int r, int v) {
    if (node[i].l == node[i].r) {
        node[i].val = v;
        node[i].gcd = v;
        return;
    }
    int mid = node[i].l + node[i].r >> 1;
    if (r <= mid) update(i << 1, l, r, v);
    else if (l > mid) update(i << 1 | 1, l, r, v);
    else {
        update(i << 1, l, mid, v);
        update(i << 1 | 1, mid + 1, r, v);
    }
    Pushup(i);
}

int query(int rt, int L,int R, int x) {
    int ans = 0;
    int mid = node[rt].l + node[rt].r >> 1;
    if (L <= node[rt].l && R >= node[rt].r && node[rt].gcd % x == 0) return 0;
    if (node[rt].l == node[rt].r) return 1;
    if (L <= mid) ans += query(rt << 1, L, R, x);
    if (ans >= 2) return ans;
    if (R > mid) ans += query(rt << 1 | 1, L, R, x);
    return ans;
}

int main() {
    int k;
    int L, R, X;
    int n = readint();
    for (int i = 1; i <= n; i++) a[i] = readint();
    Build(1, 1, n);
    int q = readint();
    while (q--) {
        k = readint();
        if (k == 1) {
            L = readint(), R = readint();
            X = readint();
            if (query(1, L, R, X) > 1) puts("NO");
            else puts("YES");
        }
        else {
            L = readint(), X = readint();
            update(1, L, L, X);
        }
    }
}
原文地址:https://www.cnblogs.com/hznumqf/p/13450730.html