http://acm.hdu.edu.cn/showproblem.php?pid=3473
对于xl,xl+1……xr,使得[xi-x]和最小,显然x应当为其中的中位数。中位数可以通过求K大数解决,划分树可搞。
对于求和,分为两部分,小于x的部分,大于y的部分,在建树的时候也保存下来分到左子树中的数的和。
最终的和为ave*(lnum-rnum)+rsum-lsum
ave为中位数,lnum为左子数的数量,也就是小于中位数的数量,rnum为右子数,lsum表示小于中位数部分的和
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define ls (rt<<1) #define rs ((rt<<1)|1) #define mid ((t[rt].l+t[rt].r)>>1) #define ll long long const int maxn = 100010; struct node { int l , r; }t[maxn<<2]; int sa[maxn],num[20][maxn],cnt[20][maxn]; ll Lsum[20][maxn],sum[maxn]; int n , q; void build(int l,int r,int rt,int deep) { t[rt].l = l; t[rt].r = r; if(l == r) return; int mid_val = sa[mid],lsum=mid-l+1; for(int i=l;i<=r;i++) if(num[deep][i] < mid_val) lsum --; int L = l , R = mid + 1; for(int i=l;i<=r;i++) { if(i == l) cnt[deep][i] = 0; else cnt[deep][i] = cnt[deep][i-1]; Lsum[deep][i]=Lsum[deep][i-1]; if(num[deep][i]<mid_val || num[deep][i]==mid_val && lsum>0) { num[deep+1][L++] = num[deep][i]; cnt[deep][i] ++; Lsum[deep][i]+=(ll)num[deep][i]; if(num[deep][i] == mid_val) lsum --; } else num[deep+1][R++] = num[deep][i]; } build(l,mid,ls,deep+1); build(mid+1,r,rs,deep+1); } int lnum; ll lsum; int query(int l,int r,int rt,int k,int deep) { if(l == r) return num[deep][l]; int s1 , s2; if(t[rt].l == l) s1 = 0; else s1 = cnt[deep][l-1]; s2 = cnt[deep][r] - s1; if(k <= s2) return query(t[rt].l+s1,t[rt].l+s1+s2-1,ls,k,deep+1); int b1 = l-1-t[rt].l+1-s1; int b2 = r-l+1-s2; lnum += s2; lsum = (ll)lsum+Lsum[deep][r]-Lsum[deep][l-1]; return query(mid+1+b1,mid+1+b1+b2-1,rs,k-s2,deep+1); } int main() { int T , cas = 1; scanf("%d" , &T); while(T--) { printf("Case #%d:\n" , cas++); scanf("%d" , &n); sum[0] = 0; for(int i=1;i<=n;i++) { scanf("%d",&num[1][i]); sa[i] = num[1][i]; sum[i] = (ll)sum[i-1] + sa[i]; } sort(sa+1,sa+1+n); build(1,n,1,1); scanf("%d",&q); while(q--) { int l , r, k; scanf("%d%d",&l,&r); l ++; r ++; k = (r-l+2)>>1; lnum = lsum = 0; int ave = query(l,r,1,k,1); printf("%I64d\n",ave*(lnum-(r-l+1-lnum))+sum[r]-sum[l-1]-lsum-lsum); } puts(""); } return 0; }