CF914D Bash and a Tough Math Puzzle
Bash and a Tough Math Puzzle
寫發部落格證明自己還活著QwQ
題目描述
Bash likes playing with arrays. He has an array of 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 of is . 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 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 . 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 queries of one of the following forms:
- — Bash guesses that the gcd of the range is . Report if this guess is almost correct.
- — Bash sets to .
Note: The array is -indexed.
題目大意
給你一個序列,要求支援單點修改,查詢一個區間是否滿足至多修改一個數使得這個區間的為。
Solution
- 很顯然的線段樹,用線段樹維護區間,單點修改的問題就解決了。
- 至於查詢的時候,因為只要有超過兩個數字不滿足條件,就可以結束判斷了;所以我們選擇線上段樹上二分,去找不滿足條件的數字,如果一個區間的不等於,就說明這個區間裡有不滿足條件的數字,到這個區間裡面找就行了,單次複雜度。
- 總複雜度
#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() {}