
- 性质1:把若干个人塞到一个连续区间内,那么从左向右依次对应一定是最优的。
- 性质2:一定存在一个分界点,左边的人都是在区间点的左边,右边的人都是在区间点的右边。
- 因此,很显然有一个
n
l
o
g
2
n
nlog^2n
nlog2n的做法,二分分界点,主席树查询第
k
k
k大判断。
- 但是,其实我们的二分是多余的,直接在主席树上二分就好了,边二分边计算答案。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+10;
const int inf=1e6;
int n,m,tot,l,r,K,sum[N*21];ll num[N*21];int ls[N*21],rs[N*21],rt[N],a[N];
ll cal(int k,int cnt){return 1LL*(k+k+cnt-1)*cnt/2;}
char buf[1<<15],*fs,*ft;
char getc(){
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
int read(){
char ch=getc();int num=0,f=1;
while(!isdigit(ch)){ch=getc();}
while(isdigit(ch)){num=(num<<1)+(num<<3)+(ch^48);ch=getc();}
return num*f;
}
void update(int &o,int pre,int l,int r,int x){
o=++tot;
sum[o]=sum[pre]+1;
num[o]=num[pre]+x;
ls[o]=ls[pre];
rs[o]=rs[pre];
if(l==r) return ;
int mid=l+r>>1;
if(x<=mid) update(ls[o],ls[pre],l,mid,x);
else update(rs[o],rs[pre],mid+1,r,x);
}
ll query(int s,int t,int l,int r,int k){
ll SUM=num[t]-num[s];
int cnt=sum[t]-sum[s];
if(!cnt) return 0;
if(l>=k) return SUM-cal(k,cnt);
if(r<=k) return cal(k,cnt)-SUM;
cnt=sum[ls[t]]-sum[ls[s]];
int mid=l+r>>1;
return query(ls[s],ls[t],l,mid,k)+query(rs[s],rs[t],mid+1,r,k+cnt);
}
ll print(ll x){if(x>9)print(x/10);putchar(x%10+'0');}
int main(){
n=read(),m=read();
for(register int i=1;i<=n;++i) a[i]=read(),update(rt[i],rt[i-1],1,inf,a[i]);
while(m--){
ll ans=0;
l=read(),r=read(),K=read();
ans=query(rt[l-1],rt[r],1,inf,K);
print(ans);puts("");
}
return 0;
}