思路:
通过前缀和和差分计算 重排前查询的区间和 与 重排后查询的区间和,输出两者之差。
关键:如何进行重排!
重排依据:是重排后的查询区间和最大,可以记录每个位置被查询的次数,将查询次数多的位置放上大的数字,依据此排序。
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
struct Num
{
int id;//记录位置信息
int cnt;//记录该位置被查询的次数
bool operator<(const Num a)const{
return cnt<a.cnt;
}
};
ll a[MAXN],b[MAXN]={0},c[MAXN];
Num num[MAXN];
int n,q;
int l[MAXN],r[MAXN];
ll sum1=0,sum2=0;
int main()
{
//输入数组a,并初始化num,计算数组a的前缀和b
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>a[i];
b[i]=b[i-1]+a[i];
num[i].id=i;
num[i].cnt=0;
}
//输入查询,通过差分法记录每个位置查询的次数
cin>>q;
for(int i=1;i<=q;++i)
{
cin>>l[i]>>r[i];
sum1+=b[r[i]]-b[l[i]-1];
num[l[i]].cnt++;
num[r[i]+1].cnt--;
}
for(int i=1;i<=n;++i)
{
num[i].cnt+=num[i-1].cnt;
}
//排序,num根据cnt排序,a从小到大排
sort(num+1,num+n+1);
sort(a+1,a+n+1);
//查询次数最小的位置放上最小的数
for(int i=1;i<=n;++i)
{
c[num[i].id]=a[i];
}
//差分前缀和 计算重排后区间和
for(int i=1;i<=n;++i)
{
b[i]=b[i-1]+c[i];
}
for(int i=1;i<=q;++i)
{
sum2+=b[r[i]]-b[l[i]-1];
}
cout<<sum2-sum1<<endl;
return 0;
}