版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88359774
洛谷传送门
BZOJ传送门
解析:
JSOI2018最简单的一道题。。。
显然有一种最优解就是保持所有同学相对位置不变。
显然所有同学向左和向右跑的决策是有一个分界线的。
直接在主席树上二分就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=1e6,M=(N+6)*20;
int rt[500005],son[M][2],cnt[M],tot;
ll sum[M];
void insert(int pre,int &now,int l,int r,int pos){
now=++tot;
cnt[now]=cnt[pre]+1;
sum[now]=sum[pre]+pos;
son[now][0]=son[pre][0];
son[now][1]=son[pre][1];
if(l==r)return ;
int mid=(l+r)>>1;
if(pos<=mid)insert(son[pre][0],son[now][0],l,mid,pos);
else insert(son[pre][1],son[now][1],mid+1,r,pos);
}
ll query(int tl,int tr,int l,int r,cs int &l1,cs int &r1){
if(r1<l1)return 0;
if(l1<=l)return sum[tr]-sum[tl]-(ll)l1*(r1-l1+1)-(ll)(r1-l1)*(r1-l1+1)/2;
if(r<=r1)return (ll)r1*(r1-l1+1)-sum[tr]+sum[tl]-(ll)(r1-l1)*(r1-l1+1)/2;
int mid=(l+r)>>1;
int delta=cnt[son[tr][0]]-cnt[son[tl][0]];
return query(son[tl][0],son[tr][0],l,mid,l1,l1+delta-1)+query(son[tl][1],son[tr][1],mid+1,r,l1+delta,r1);
}
int n,m;
signed main(){
n=getint(),m=getint();
for(int re i=1;i<=n;++i)insert(rt[i-1],rt[i],1,N,getint());
int l,r,K;
while(m--){
l=getint(),r=getint(),K=getint();
cout<<query(rt[l-1],rt[r],1,N,K,K+r-l)<<"\n";
}
return 0;
}