题解:P12644 [KOI 2024 Round 1] 会议地点
return_liang · · 题解
思路
首先对于每个会议集合,它的疲劳度应该是会议集合里最大的开销值-最小的开销值。
那么对于每个询问的会议集合,它的最大的开销值和最小的开销值怎么算呢?
注:接下来出现的所有
我们首先可以想到每个居民的开销值可以通过前缀和和后缀和计算出来的:
对于会议地点
其中
知道了怎么在
首先对于一个会议集合
那么怎么比较呢?我们可以想到如果把会议地点由
显然每个会议集合内的最小开销值一定是
而每个会议集合内的最大开销值是
那么最后就能在
代码
#include <bits/stdc++.h>
using namespace std;
const long long L=1e9;
long long x[200005], lsum[200005], rsum[200005];//开long long
long long getl(long long l, long long r){//前缀和求以l为会议地点,包含[l, r]的居民作为参与者时的开销值
return lsum[r]-lsum[l-1]-x[l]*(r-l+1);
}
long long getr(long long l, long long r){//后缀和求以r为会议地点,包含[l, r]的居民作为参与者时的开销值
return rsum[l]-rsum[r+1]-(L-x[r])*(r-l+1);
}
int main(){
long long n, q, l, r;
cin >> n >> q;
for(long long i=1;i <= n;i++){
cin >> x[i];
lsum[i]=lsum[i-1]+x[i];
}
for(long long i=n;i >= 1;i--){
rsum[i]=rsum[i+1]+L-x[i];
}
for(long long i=1;i <= q;i++){
cin >> l >> r;
//二分求出居民点下标的左右界
r=upper_bound(x+1, x+1+n, r)-x-1;
l=lower_bound(x+1, x+1+n, l)-x;
long long mid=(l+r)/2, ma, mi;
ma=max(getl(l, r), getr(l, r));
mi=getl(mid, r)+getr(l, mid);
cout << ma-mi << "\n";
}
return 0;
}