题目传送门

因为老登不写题解,所以25届小凳来补一篇

数据预处理

最开始,很容易发现,选择负数的美丽贡献度是没有意义的,因为这会使得结果一定小于0,不如选择0朵玫瑰,所以我们在预处理的时候,将负数处理成0

区间查询

很容易知道,这时候贪心是最好的选择,我们要尽可能地选择更多的正数,因为最开始负数已经被处理掉,0也不会影响运算,所以我们可以选择将整个区间囊括,对于区间查询,我们很容易想到一个万能大法——前缀和,但是很遗憾,这是行不通的,这也算是题目的一大坑点
我们不妨回忆一下前缀和,我们使用了加法的逆运算——减法 ,还原了数字原本的值,但是按位或不存在逆运算,所以前缀和行不通,所以我们选择线段树查询,当然也可以用树状数组,读者自写不难(bushi)
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
const int maxn = 5e5;
ll tree[maxn<<2];ll num[maxn];

inline void up(int p) {tree[p] = tree[p<<1]|tree[p<<1|1];}

void build(int s,int t,int p) {
    if(s==t) {
        tree[p] = num[s];
        return;
    }
    int mid = s+((t-s)>>1);
    build(s,mid,p<<1);
    build(mid+1,t,p<<1|1);
    up(p);
}

ll get_sum(int l,int r,int s,int t,int p) {
    if(l<=s && r>=t) return tree[p];
    int mid = s+((t-s)>>1);
    ll ans = 0;
    if(l<=mid) ans |= get_sum(l,r,s,mid,p<<1);
    if(r>=mid+1) ans |=get_sum(l,r,mid+1,t,p<<1|1);
    return ans;
}

int main()
{
    cin.tie(nullptr)->sync_with_stdio(false);
    int n;cin >> n;ll x;
    for(int i = 1;i<=n;i++) {
        cin >> x;
        if(x<0)x=0;
        num[i] = x;
    }
    build(1,n,1);
    int p;cin >> p;int li,ri;
    for(int i = 1;i<=p;i++) {
        cin >> li >> ri;
        cout << get_sum(li,ri,1,n,1) << endl;
    }
}
小凳学识尚浅,各路大佬轻喷