题意:给出一个长度为n的数列,m次询问区间合值,现在要求把数列重新排序使m次询问合值累加最大
其实就是某个位置上次数越多使得乘积的数越大,贪心一下,树状数组或者线段树随便搞搞,统计每个位置的询问次数,将次数和原数列从大到小排,依次乘积相加
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 200005
long long a[maxn];
long long c[2][maxn];
long long num[maxn];
int n,m;
inline int lowbit(int x)
{
return x&-x;
}
inline void update(int x,int val)
{
for(int i=x;i<=n;i+=lowbit(i)) c[0][i]+=val,c[1][i]+=(x-1)*val;
}
inline long long query(int x)
{
long long sum1=0,sum2=0;
for(int i=x;i>0;i-=lowbit(i)) sum1+=c[0][i],sum2+=c[1][i];
return x*sum1-sum2;
}
bool cmp(long long a,long long b)
{
return a>b;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
}
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
update(r+1,-1);
update(l,1);
}
for(int i=1;i<=n;i++)
{
num[i]=query(i)-query(i-1);
}
sort(a+1,a+n+1,cmp);
sort(num+1,num+n+1,cmp);
long long ans=0;
for(int i=1;i<=n;i++)
{
ans+=num[i]*a[i];
}
printf("%I64d\n",ans);
return 0;
}