势能线段树
势能!(到0不用更新,直接返回),根据题目是否有这一点来进行更新,从而优化时间复杂度

现在给定一个长度为 NN 的序列,现在要对这个序列进行 MM 次操作, AND : L , R , vAND:L,R,v 将区间中元素a_iai (L \leqslant i \leqslant R)(L⩽i⩽R),将 a_iai 修改为a_iai & v ,(&是按位与) UPD:X , v:UPD:X,v: 将 a[x] 修改为 v QUE:L , R:QUE:L,R: 询问 a_iai 的最大值(L \leqslant i \leqslant R)(L⩽i⩽R) 宋老板希望你能够写一个程序,支持以上操作。Tips:Tips:(1 \leqslant(1⩽vv\leqslant⩽ 2^{30} - 1230−1) ,(1 \leqslant L,R,x \leqslant n)(1⩽L,R,x⩽n) Input 第一行包括两个数字N,MN,M(1 \leqslant N,M \leqslant 400000)(1⩽N,M⩽400000),分别表示序列的长度和多少次操作 第二行包括 NN 个数字a_1,a_2...a_na1,a2...an表示序列的初始状态 (1 \leqslant(1⩽a_i~ai \leqslant⩽2^{30}230) 接下来的 MM 行,每一行都描述一种操作。 Output 对于每一个 QUEQUE 操作输出一个整数表示答案。 数据保证一定会有至少一次 QUEQUE 操作. Example Input 5 11 5 6 7 8 9 AND 1 3 5 UPD 1 10 AND 3 4 2 UPD 1 7 QUE 1 5 AND 2 5 8 AND 4 5 3 UPD 4 1 QUE 1 5 UPD 3 12 QUE 1 5 Output 9 7 12

#include <iostream> #include <fstream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <queue> #include <stack> #include <vector> #include <map> #include <set> #include<bitset> #pragma warning(disable:4996) #pragma GCC optimize (2) #pragma G++ optimize (2) #define inr register int #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define debug(a) cout << #a << " " << a << endl using namespace std; typedef long long long long; const double pi = acos(-1.0); const double eps = 1e-8; const int inf = 0x3f3f3f3f; const int 1000007 = 400007;//1e5+7 int read() { int res = 0, ch, flag = 0; if ((ch = getchar()) == '-') flag = 1; else if (ch >= '0' && ch <= '9') res = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') res = res * 10 + ch - '0'; return flag ? -res : res; } #define lson (o<<1) #define rson (o<<1|1) int arr[1000007]; struct node { int mx; int tag; }tree[1000007 << 2]; inline void pushup(int o) { tree[o].mx = max(tree[lson].mx, tree[rson].mx); tree[o].tag = tree[lson].tag | tree[rson].tag;//收集区间内所有位权1,作为势能函数 } void build(int o, int l, int r) { if (l == r) { tree[o] = { arr[l] , arr[l] }; return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); pushup(o); } void modify(int o, int l, int r, int ml, int mr, int x) { if (!((~x) & tree[o].tag)) { return; } if (l == r) { tree[o].mx &= x; tree[o].tag &= x; return; } int mid = (l + r) >> 1; if (ml <= mid) { modify(lson, l, mid, ml, mr, x); } if (mid + 1 <= mr) { modify(rson, mid + 1, r, ml, mr, x); } pushup(o); } void update(int o, int l, int r, int p, int x) { if (l == r) { tree[o] = { x,x }; return; } int mid = (l + r) >> 1; if (p <= mid) { update(lson, l, mid, p, x); } else { update(rson, mid + 1, r, p, x); } pushup(o); } int query(int o, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) { return tree[o].mx; } int mid = (l + r) >> 1, res = 0; if (ql <= mid) { res = max(res, query(lson, l, mid, ql, qr)); } if (mid + 1 <= qr) { res = max(res, query(rson, mid + 1, r, ql, qr)); } return res; } char st[17]; int main() { int n = read(), m = read(); for (int i = 1; i <= n; i++) { arr[i] = read(); } build(1, 1, n); int opl, opr, opx; while (m--) { scanf("%s%d", st, &opl); if (st[0] == 'A') { opr = read(); opx = read(); modify(1, 1, n, opl, opr, opx); } else if (st[0] == 'U') { opx = read(); update(1, 1, n, opl, opx); } else { opr = read(); printf("%d\n", query(1, 1, n, opl, opr)); } } return 0; }
此题注意 位运算的魅力。
推荐博客:(17条消息) 势能线段树(吉司机线段树)专题_jibinquan的博客-CSDN博客_势能线段树