题目传送门
因为老登不写题解,所以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;
}
}
小凳学识尚浅,各路大佬轻喷

京公网安备 11010502036488号