分析
显然我们以中位数为目标最佳(我赛场打了splay???(干什么不打Treap))
那么用传统的双堆法求中位数即可
#include <iostream> #include <cstdio> #include <queue> using namespace std; typedef long long ll; const int N=1010; priority_queue<ll> b; priority_queue<ll,vector<ll>,greater<ll> > a; ll ans[N][N],h[N],suma,sumb,cnta,cntb; int n,m; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%lld",&h[i]); for (int i=1;i<=n;i++) { while (!a.empty()) a.pop(); while (!b.empty()) b.pop(); suma=sumb=cnta=cntb=0; a.push(h[i]);cnta=1;suma+=h[i]; for (int j=i+1;j<=n;j++) { if (cnta==cntb) { if (h[j]>=b.top()) a.push(h[j]),cnta++,suma+=h[j]; else { ll x=b.top(); b.pop();sumb-=x;a.push(x);suma+=x;cnta++;b.push(h[j]);sumb+=h[j]; } } else if (h[j]<=a.top()) b.push(h[j]),cntb++,sumb+=h[j]; else { ll x=a.top(); a.pop();suma-=x;b.push(x);sumb+=x;cntb++;a.push(h[j]);suma+=h[j]; } ans[i][j]=suma-cnta*a.top()+a.top()*cntb-sumb; } } ll lans=0; for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); lans+=ans[x][y]; } printf("%lld ",lans); }