#include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 1E5 + 10; int T, m, n, inp[maxn], l, r, op, x; struct Node { int l, r, val; bool update; std::vector<int> X; }; Node node[maxn * 4]; void Build(int l, int r, int idx) { node[idx].l = l; node[idx].r = r; node[idx].update = false, node[idx].X.clear(); if (l == r) {node[idx].val = inp[l]; return;} else { int mid = (l + r) >> 1; Build(l, mid, idx << 1); Build(mid + 1, r, idx << 1 | 1); } } void Push(int idx) { if (node[idx].l == node[idx].r) return ; if (node[idx].update) { node[idx << 1].val = node[idx << 1 | 1].val = node[idx].val; node[idx << 1].update = node[idx << 1 | 1].update = true; node[idx].update = false; node[idx << 1].X = node[idx << 1 | 1].X = node[idx].X; } else for (int i = 0; i < node[idx].X.size(); i++) { node[idx << 1].X.push_back(node[idx].X[i]); node[idx << 1 | 1].X.push_back(node[idx].X[i]); } node[idx].X.clear(); } void Update(int l, int r, int idx, int val, int op) { Push(idx); if (node[idx].l == l && node[idx].r == r) { if (op == 1) node[idx].val = val, node[idx].X.clear(), node[idx].update = true; else if (op == 2) node[idx].X.push_back(val); else { for (int i = 0; i < node[idx].X.size(); i++) if (node[idx].val > node[idx].X[i]) { node[idx].val = __gcd(node[idx].val, node[idx].X[i]); if (node[idx].val == 1) break; } inp[node[idx].l] = node[idx].val; } } else { int mid = (node[idx].l + node[idx].r) >> 1; if (r <= mid) Update(l, r, idx << 1, val, op); else if (l > mid) Update(l, r, idx << 1 | 1, val, op); else { Update(l, mid, idx < 1, val, op); Update(mid + 1, r, idx << 1 | 1, val, op); } } } int main(int argc, char const *argv[]) { scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", inp + i); Build(1, n, 1); scanf("%d", &m); while (m--) { scanf("%d%d%d%d", &op, &l, &r, &x); Update(l, r, 1, x, op); } for (int i = 1; i <= n; i++) Update(i, i, 1, 0, 3); for (int i = 1; i <= n; i++) printf("%d%c", inp[i], ' '); printf("\n"); } return 0; }
解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是把区间 (l,r) 中大于x的数跟 x 做gcd操作。
线段树区间更新的题目,每个节点保存一个最大和最小值,当该节点的最大值和最小值相等的时候表示这个区间所有的数字都是相同的,可以直接对这个区间进行1或2操作,
进行1操作时,当还没有到达要操作的区间但已经出现了节点的最大值跟最小值相等的情况时,说明这个区间的值都是相同的,但现在我只要在这个区间的一部分进行1操作,所以我要先把这个节点的最大的最小值往下压,直到找到了要操作的区间。
进行2操作时,如果该区间的最大值都小于x,则可以直接退出,如果最大值大于x,则表示这个区间可以进行gcd操作,然后继续往下,直到找到最大值跟最小值相等的区间才开始进行gcd操作,进行gcd操作之后不要忘了更新父节点的最大最小值。