[BZOJ5319]
- 显然对于一个询问,我们应该将被询问的人以及询问的位置排序后一一匹配
- 也就是排序后求 \sum=|Ai−Bi|
- 由于人的位置互不相同,所以A数组是递增的,而B数组是连续的一段整数,因此Ai与Bi的大小关系只有可能由小于到大于变化一次
- 对原序列建立主席树,询问时在对应区间上二分出大小关系变化的位置,前后用区间和计算答案即可
- 时间复杂度O((n+m)logk)
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define ll long long
using namespace std;
const int inf=1e6;
const int N=5e5+10;
int lc[N*21],rc[N*21],cnt[N*21],root[N],tot,l,r,k,n,m;
ll sum[N*21];
inline int read(){
int num=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))num=num*10+ch-'0',ch=getchar();
return num;
}
inline ll print(ll x){if(x>9)print(x/10);putchar(x%10+'0');}
void update(int &o,int last,int L,int R,int val){
int M=L+R>>1;
o=++tot,lc[o]=lc[last],rc[o]=rc[last],sum[o]=sum[last]+val,cnt[o]=cnt[last]+1;
if(L==R)return;
if(val<=M)update(lc[o],lc[last],L,M,val);
else update(rc[o],rc[last],M+1,R,val);
}
inline ll cal(int k,int cnt){return 1LL*(k+k+cnt-1)*cnt/2;}
ll query(int now,int last,int L,int R,int k){
int M=L+R>>1;
int CNT=cnt[now]-cnt[last];
ll SUM=sum[now]-sum[last];
if(CNT==0)return 0;
if (L>=k) return SUM-cal(k,CNT);
if (R<=k) return cal(k,CNT)-SUM;
int tmp=cnt[lc[now]]-cnt[lc[last]];
return query(lc[now],lc[last],L,M,k)+query(rc[now],rc[last],M+1,R,k+tmp);
}
int main()
{
//freopen("a.in","r",stdin);
n=read(),m=read();
rep(i,1,n){
k=read();
update(root[i],root[i-1],1,inf,k);
}
while(m--){
l=read(),r=read(),k=read();
print(query(root[r],root[l-1],1,inf,k));
puts("");
}return 0;
}