有n个数,每次给出一段区间l,r,选出一个数X使得|X-Xi|(l<=i<=r)尽量小,X显然是中位数。此外还要得到区间和,这个可以在划分树递归的时候累加,当递归左子树的时候,可以加上所有大于中位数的数,递归右子树的时候可以减去所有小于中位数的数。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef __int64 LL; const int maxn = 100010; int tree[20][maxn], toleft[20][maxn], a[maxn]; LL sum[20][maxn]; void build(int l, int r, int dep) { if(l == r) { sum[dep][l] = tree[dep][l]; return; } int m = (l+r) >> 1; int tol = m-l+1; for(int i = l; i <= r; i++) { if(tree[dep][i] < a[m]) tol--; sum[dep][i] = tree[dep][i]; if(i > l) sum[dep][i] += sum[dep][i-1]; } int L = l, R = m+1; for(int i = l; i <= r; i++) { if(tree[dep][i] < a[m]) tree[dep+1][L++] = tree[dep][i]; else if(tree[dep][i] == a[m] && tol > 0) { tree[dep+1][L++] = tree[dep][i]; tol--; } else tree[dep+1][R++] = tree[dep][i]; toleft[dep][i] = toleft[dep][l-1] + L-l; } build(l, m, dep+1); build(m+1, r, dep+1); } LL ans; int query(int L, int R, int l, int r, int dep, int k) { if(l == r) return tree[dep][l]; int m = (L+R) >> 1; int cnt = toleft[dep][r]-toleft[dep][l-1]; int ltol = toleft[dep][l-1]-toleft[dep][L-1]; int ltor = l-L-ltol; int mtol = cnt; int mtor = r-l+1-cnt; if(cnt >= k) { if(mtor > 0) { if(ltor > 0) ans += sum[dep+1][mtor+ltor+m]-sum[dep+1][ltor+m]; else ans += sum[dep+1][mtor+m]; } int nextl = L + toleft[dep][l-1]-toleft[dep][L-1]; int nextr = nextl + cnt - 1; return query(L, m, nextl, nextr, dep+1, k); } else { if(mtol > 0) { if(ltol > 0) ans -= sum[dep+1][mtol+ltol+L-1]-sum[dep+1][ltol+L-1]; else ans -= sum[dep+1][mtol+L-1]; } int nextr = r + toleft[dep][R]-toleft[dep][r]; int nextl = nextr-(r-l-cnt); return query(m+1, R, nextl, nextr, dep+1, k-cnt); } } int main() { int T, cas = 1; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &tree[0][i]); a[i] = tree[0][i]; } sort(a+1, a+n+1); int q; scanf("%d", &q); build(1, n, 0); printf("Case #%d:\n", cas++); while(q--) { int l, r; scanf("%d %d", &l, &r); l++, r++; ans = 0; int m = (r-l)/2+1; int tmp = query(1, n, l, r, 0, m); if((r-l+1)%2 == 0) ans -= tmp; printf("%I64d\n", ans); } puts(""); } return 0; }