势能线段树


势能!(到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
View problem
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include <set>
#include
#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博客_势能线段树