标签:划分树
划分树。只是考虑求当前区间大于第k值的值得和,和小于第k值的和。显然可以在查询的时候直接搞出来。sum[d][i]表示第d层子区间l,r种l-i的和。写错了一个下标,检查了半辈子。。。
#include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define MP make_pair #define LL long long #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; #define MID ((l+r)>>1) const int maxn = 100100; const int INF = 0x3f3f3f3f; struct KthNumber { int a[maxn], s[maxn], t[20][maxn], num[20][maxn]; LL sum[20][maxn]; void init(int n) { for(int i = 1; i <= n; i ++) { scanf("%d", &a[i]); s[i] = t[0][i] = a[i]; } sort(s+1, s+n+1); } void Build(int d, int l, int r) { int lm = MID-l+1, lp = l, rp = MID+1; for(int i = l; i <= MID; i ++) lm -= s[i] < s[MID]; for(int i = l; i <= r; i ++) { if(i == l) num[d][i] = 0, sum[d][i] = 0; else num[d][i] = num[d][i - 1], sum[d][i] = sum[d][i-1]; if(t[d][i] == s[MID]) { if(lm) { lm --; num[d][i] ++; t[d+1][lp++] = t[d][i]; } else t[d+1][rp++] = t[d][i]; } else if(t[d][i] < s[MID]) { num[d][i] ++; t[d+1][lp++] = t[d][i]; } else t[d+1][rp++] = t[d][i]; sum[d][i] += t[d][i]; } if(l<r) Build(d+1, l, MID), Build(d+1, MID+1, r); } int Query(int d, int l, int r, int ql, int qr, int k) { if(l == r) return t[d][l]; int s, ss; if(l == ql) s = 0, ss = num[d][qr]; else s = num[d][ql-1], ss = num[d][qr]-num[d][ql-1]; if(k <= ss) return Query(d+1, l, MID, l+s, l+s+ss-1, k); else return Query(d+1, MID+1, r, MID+1+ql-l-s, MID+1+qr-l-s-ss, k-ss); } int val; LL Query2(int d, int l, int r, int ql, int qr, int k) { if(l == r) { val = t[d][l]; return 0; } int s, ss;LL ret; if(l == ql) s = 0, ss = num[d][qr]; else s = num[d][ql-1], ss = num[d][qr]-num[d][ql-1]; int l1 = l+s, r1 = l+s+ss-1, l2 = MID+1+ql-l-s, r2 = MID+1+qr-l-s-ss; if(k <= ss) { ret = Query2(d+1, l, MID, l1, r1, k); if(l2 <= r2) ret += sum[d+1][r2] - (l2 == MID+1 ? 0 : sum[d+1][l2 - 1]) - (r2-l2+1ll)*val; } else { ret = Query2(d+1, MID+1, r, l2, r2, k-ss); if(l1 <= r1) ret += (r1-l1+1ll)*val - sum[d+1][r1] + (l1 == l ? 0 : sum[d+1][l1 - 1]); } return ret; } }sol; int main() { int n, m, T, cas = 1; scanf("%d", &T); while(T --) { scanf("%d", &n); sol.init(n); sol.Build(0, 1, n); scanf("%d", &m); printf("Case #%d:\n", cas ++); while(m --) { int l, r, k; scanf("%d%d", &l, &r); l ++, r ++;k = (r-l+2)/2; printf("%I64d\n", sol.Query2(0, 1, n, l, r, k)); } puts(""); } }
hdu 3473 Minimum Sum(划分树-sum操作),布布扣,bubuko.com
hdu 3473 Minimum Sum(划分树-sum操作)
标签:划分树
原文地址:http://blog.csdn.net/ok_again/article/details/25790961