1. 程式人生 > >CF914D Bash and a Tough Math Puzzle

CF914D Bash and a Tough Math Puzzle

Bash and a Tough Math Puzzle

寫發部落格證明自己還活著QwQ

題目描述

Bash likes playing with arrays. He has an array a1,a2,...ana_{1},a_{2},...\ a_{n} of nn integers. He likes to guess the greatest common divisor (gcd) of different segments of the array. Of course, sometimes the guess is not correct. However, Bash will be satisfied if his guess is almost correct. Suppose he guesses that the gcd of the elements in the range [

l,r][l,r] of aa is xx . He considers the guess to be almost correct if he can change at most one element in the segment such that the gcd of the segment is xx after making the change. Note that when he guesses, he doesn’t actually change the array — he just wonders if the gcd of the segment can be made x
x
. Apart from this, he also sometimes makes changes to the array itself. Since he can’t figure it out himself, Bash wants you to tell him which of his guesses are almost correct. Formally, you have to process qq queries of one of the following forms:

  • 1lrx1 \ l\ r\ x — Bash guesses that the gcd of the range [
    l,r][l,r]
    is xx . Report if this guess is almost correct.
  • 2iy2 \ i \ y — Bash sets aia_{i} to yy .

Note: The array is 11 -indexed.

題目大意

給你一個序列,要求支援單點修改,查詢一個區間是否滿足至多修改一個數使得這個區間的GCDGCDxx

Solution

  • 很顯然的線段樹,用線段樹維護區間GCDGCD,單點修改的問題就解決了。
  • 至於查詢的時候,因為只要有超過兩個數字不滿足條件,就可以結束判斷了;所以我們選擇線上段樹上二分,去找不滿足條件的數字,如果一個區間的GCDGCD不等於xx,就說明這個區間裡有不滿足條件的數字,到這個區間裡面找就行了,單次複雜度O(logn)O(logn)
  • 總複雜度O(nlog2n)O(nlog^2n)
#include<cstdio>

const int maxn = 5e5 + 7;

class SegmentTree{
private :
    struct Node{
        Node *child[2];
        int left, right, val;

        Node (int left = 0, int right = 0) :
            left(left),
            right(right) {
            child[0] = NULL;
            child[1] = NULL;
        }
    };
    Node *root;
    int sum;

    int Gcd(int x, int y) {
        if (!x) {
            return y;
        }
        return Gcd(y % x, x);
    }

    void BuildTree(Node *now, int *a) {
        if (now->left == now->right) {
            now->val = a[now->left];
            return;
        }
        int mid = now->left + now->right >> 1;
        now->child[0] = new Node(now->left, mid);
        now->child[1] = new Node(mid + 1, now->right);
        BuildTree(now->child[0], a), BuildTree(now->child[1], a);
        Update(now);
    }

    void Update(Node *now) {
        now->val = Gcd(now->child[0]->val, now->child[1]->val);
    }

    void Change(Node *now, int pos, int x) {
        if (now->left == now->right) {
            now->val = x;
            return;
        }
        int mid = now->left + now->right >> 1;
        if (pos <= mid) {
            Change(now->child[0], pos, x);
        } else {
            Change(now->child[1], pos, x);
        }
        Update(now);
    }

    void Query(Node *now, int x, int l, int r) {
        if (sum > 1) {
            return;
        }
        if (now->left == now->right) {
            if (now->val % x != 0) {
                sum++;
            }
            return;
        }
        if (now->left >= l && now->right <= r) {
            if (now->val % x != 0) {
                Query(now->child[0], x, l, r);
                Query(now->child[1], x, l, r);
            }
            return;
        }
        int mid = now->left + now->right >> 1;
        if (r <= mid) {
            Query(now->child[0], x, l, r);
        } else if (l > mid) {
            Query(now->child[1], x, l, r);
        } else {
            Query(now->child[0], x, l, r), Query(now->child[1], x, l, r);
        }
    }

public :
    void Init(int n, int *a) {
        root = new Node(1, n);
        BuildTree(root, a);
    }

    void Change(int pos, int x) {
        Change(root, pos, x);
    }

    bool Query(int l, int r, int x) {
        sum = 0;
        Query(root, x, l, r);
        return sum <= 1;
    }
};

class Solution{
private :
    int n, m, a[maxn];
    SegmentTree tree;
    
public :
    Solution() {
        Get();
        Solve();
    }

    void Get() {
        scanf("%d", &n);
        for (register int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        tree.Init(n, a);
    }

    void Solve() {
        scanf("%d", &m);
        for (register int i = 1; i <= m; i++) {
            int op, l, r, x, y;
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d %d %d", &l, &r, &x);
                if (tree.Query(l, r, x)) {
                    printf("YES\n");
                } else {
                    printf("NO\n");
                }
            } else {
                scanf("%d %d", &x, &y);
                tree.Change(x, y);
            }
        }
    }
};
Solution sol;

int main() {}