HYSBZ - 5312 冒险

题意:

给定一个长度为 n n n 的数组 a a a,有 q q q 次操作,① 1 , l , r , x 1, l, r, x 1,l,r,x,区间 &   x \&~x & x;② 2 , l , r , x 2, l, r, x 2,l,r,x,区间 ∣   x \mid~x  x;③ 3 , l , r 3, l, r 3,l,r,查询区间最大值。 ( n , q ≤ 2 × 1 0 5 , 0 ≤ a i ≤ 2 20 ) (n, q \leq 2×10^5, 0 \leq a_i \leq 2^{20}) (n,q2×105,0ai220)

链接:

https://vjudge.net/problem/HDU-5828

解题思路:

位运算考虑拆位用线段树维护,但需要维护的是最值,不像区间和可以分开维护。区间 &   x \&~x & x,最值可以直接维护当且仅当区间所有数相同,更进一步考虑,将每个位分开更新,某个位可以直接更新当且仅当区间所有数该位相同。那么分每个位考虑操作, &   x \&~x & x,当 x i = 0 x_i = 0 xi=0 有效,区间赋值 0 0 0 ∣   x \mid~x  x,当 x i = 1 x_i = 1 xi=1 有效,区间赋值 1 1 1,区间直接更新当且仅当区间所有数该位相同,定义结点势能为 0 0 0 当且仅当满足该位相同,否则为 1 1 1。注意以下讨论仍只考虑单个二进制位,其他各位同理。初始总势能为 O ( n l o g n ) O(nlogn) O(nlogn),更新时先定位 O ( l o g n ) O(logn) O(logn) 个区间,若区间该位不全相同,即势能非 0 0 0,那么暴力向下访问,回溯时势能清 0 0 0,暴力访问的结点数与势能同阶。

综上,对每位单独考虑更新即可,但不必也不能分开用多棵线段树维护。总复杂度 O ( n l o g n l o g a + m l o g n ) O(nlognloga + mlogn) O(nlognloga+mlogn)

参考代码:
#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int msk = (1 << 21) - 1;
int a[maxn];
int n, m;

struct SegTree{

    int mx[maxn << 2], equ[maxn << 2], tad[maxn << 2], tor[maxn << 2];
    void pushUp(int rt){

        mx[rt] = max(mx[lson], mx[rson]);
        equ[rt] = equ[lson] & equ[rson] & (mx[lson] ^ mx[rson] ^ msk);
    }
    void build(int l, int r, int rt){

        tad[rt] = msk, tor[rt] = 0;
        if(l == r){

            mx[rt] = a[l], equ[rt] = msk;
            return;
        }
        int mid = gmid;
        build(l, mid, lson);
        build(mid + 1, r, rson);
        pushUp(rt);
    }
    void pushDown2(int rt, int son){

        tad[son] &= tad[rt];
        tor[son] &= tad[rt];
        mx[son] &= tad[rt];

        tor[son] |= tor[rt];
        mx[son] |= tor[rt];
    }
    void pushDown(int rt){

        pushDown2(rt, lson);
        pushDown2(rt, rson);
        tad[rt] = msk, tor[rt] = 0;
    }
    void updateAnd(int l, int r, int rt, int L, int R, int val){

        if(l >= L && r <= R){

            tad[0] = (val ^ msk) & equ[rt] ^ msk, tor[0] = 0;
            pushDown2(0, rt);
            val ^= tad[0] ^ msk;
            if(val == msk) return;
        }
        int mid = gmid;
        pushDown(rt);
        if(L <= mid) updateAnd(l, mid, lson, L, R, val);
        if(R > mid) updateAnd(mid + 1, r, rson, L, R, val);
        pushUp(rt);
    }
    void updateOr(int l, int r, int rt, int L, int R, int val){

        if(l >= L && r <= R){

            tad[0] = msk, tor[0] = val & equ[rt];
            pushDown2(0, rt);
            val ^= tor[0];
            if(!val) return;
        }
        int mid = gmid;
        pushDown(rt);
        if(L <= mid) updateOr(l, mid, lson, L, R, val);
        if(R > mid) updateOr(mid + 1, r, rson, L, R, val);
        pushUp(rt);
    }
    int query(int l, int r, int rt, int L, int R){

        if(l >= L && r <= R) return mx[rt];
        int mid = gmid, ret = 0;
        pushDown(rt);
        if(L <= mid) ret = max(ret, query(l, mid, lson, L, R));
        if(R > mid) ret = max(ret, query(mid + 1, r, rson, L, R));
        return ret;
    }
} tr;

int main(){

    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= n; ++i){

        cin >> a[i];
    }
    tr.build(1, n, 1);
    while(m--){

        int opt, x, y, z; cin >> opt >> x >> y;
        if(opt == 1){

            cin >> z;
            tr.updateAnd(1, n, 1, x, y, z);
        }
        else if(opt == 2){

            cin >> z;
            tr.updateOr(1, n, 1, x, y, z);
        }
        else{

            int ret = tr.query(1, n, 1, x, y);
            cout << ret << "\n";
        }
    }
    return 0;;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值