题意: 有n个人 每个人有其一开始所在的位置   有m个询问   l r k    问编号为l到r的人填满区间 k----k+r-l  需要的最少距离

很容易发现按照原来的相对位置来填k开始的位置肯定是一种最优解

lr的编号区间很容易想到主席树

所以问题转化为如何优化主席树的询问   

1、如果遍历每个人 然后累和每个人的距离 肯定会超时  复杂度接近on

2、可以分三种情况讨论

  如果所有的人都在   应到位置的左边  那么贡献为

  如果所有的人都在    应到位置的右边 那么贡献为 

  否则的话递归到子树继续进行分类

学会了主席树一种新的查询方式!!!

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define pb push_back
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
typedef pair<int,int>pii;
//////////////////////////////////
const int N=1e6+10;
int T[N],lson[N<<5],rson[N<<5],ncnt,n,m;
ll t[N<<5],sum[N<<5];
void upnode(int x,int l,int r,int pre,int &pos)
{
    pos=++ncnt;
    lson[pos]=lson[pre];rson[pos]=rson[pre];
    t[pos]=t[pre]+1;
    sum[pos]=sum[pre]+x;
    int m=(l+r)>>1;
    if(l==r)return ;
    if(x<=m)upnode(x,l,m,lson[pre],lson[pos]);
    else upnode(x,m+1,r,rson[pre],rson[pos]);
}
ll qsum(int L,int R,int l,int r,int pre,int pos)
{
    if(L>R)return 0;
    if(r<=L)return 1ll*(L+R)*(R-L+1)/2-(sum[pos]-sum[pre]);
    if(l>=R)return  (sum[pos]-sum[pre])-1ll*(L+R)*(R-L+1)/2;
    if(l==r)return 0;int m=(l+r)>>1;
    int peo=t[lson[pos]]-t[lson[pre]];
    return qsum(L,L+peo-1,l,m,lson[pre],lson[pos])+qsum(L+peo,R,m+1,r,rson[pre],rson[pos]);
}
int main()
{
    scanf("%d%d",&n,&m);int x;
    rep(i,1,n)scanf("%d",&x),upnode(x,1,1e6,T[i-1],T[i]);
    int l,r,k;
    while(m--)
    {
        scanf("%d%d%d",&l,&r,&k);
        printf("%lld\n",qsum(k,k+r-l,1,1e6,T[l-1],T[r]));
    }
    return 0;
}
View Code
02-13 17:45