hdu 3473 划分树 ***
题目大意:有一个数列 x1..xn,要求一个数x使得 sigma(abs(xi-x))值最小,很明显,对数列进行排序后最中间的那个数就是x,可用划分树求得,那么如何求和呢,经过计算可知,既然
x 是最中间的那个数,那么最后的和 即为 x左边 xmid-x1+xmid-x2.. + x(mid+1) - xmid + x(mid+2)-xmid.. 整理得 xmid*(lefnum-rignum)+rigsum-lefsum
lefnum为划分过程进入左子树的个数,lefsum为进入左子树的数之和
lefsum求法:在划分过程,当该层 有数进入左子树即 加上 该数,具体见代码。。
需要理解划分树
链接:点我
1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <string.h> 5 using namespace std; 6 const int MAXN = 100010; 7 int tree[20][MAXN]; 8 int sorted[MAXN]; 9 int toleft[20][MAXN]; 10 long long sum[20][MAXN]; 11 12 void build(int l,int r,int dep) 13 { 14 if(l == r) 15 { 16 sum[dep][l] = sum[dep][l-1]+tree[dep][l]; 17 return; 18 } 19 int mid = (l+r)>>1; 20 int same = mid - l + 1; 21 for(int i = l;i <= r;i++) 22 { 23 if(tree[dep][i] < sorted[mid]) 24 same--; 25 sum[dep][i] += sum[dep][i-1]+tree[dep][i]; 26 } 27 int lpos = l; 28 int rpos = mid+1; 29 for(int i = l;i <= r;i++) 30 { 31 if(tree[dep][i] < sorted[mid]) 32 tree[dep+1][lpos++] = tree[dep][i]; 33 else if(tree[dep][i] == sorted[mid] && same > 0) 34 { 35 tree[dep+1][lpos++] = tree[dep][i]; 36 same--; 37 } 38 else 39 tree[dep+1][rpos++] = tree[dep][i]; 40 toleft[dep][i] = toleft[dep][l-1] + lpos - l; 41 } 42 build(l,mid,dep+1); 43 build(mid+1,r,dep+1); 44 } 45 long long ans; 46 int query(int L,int R,int l,int r,int dep,int k) 47 { 48 if(l == r)return tree[dep][l]; 49 int mid = (L+R)>>1; 50 int cnt = toleft[dep][r] - toleft[dep][l-1]; 51 if(cnt >= k) 52 { 53 int ee = r-L+1-(toleft[dep][r]-toleft[dep][L-1])+mid; 54 int ss = l-L-(toleft[dep][l-1]-toleft[dep][L-1])+mid; 55 56 ans += sum[dep+1][ee]-sum[dep+1][ss]; 57 58 int newl = L + toleft[dep][l-1]-toleft[dep][L-1]; 59 int newr = newl + cnt -1; 60 return query(L,mid,newl,newr,dep+1,k); 61 } 62 else 63 { 64 int s = L + toleft[dep][l-1] - toleft[dep][L-1]; 65 int e = s + cnt - 1; 66 67 ans -= sum[dep+1][e] - sum[dep+1][s-1]; 68 69 int newr = r + toleft[dep][R] - toleft[dep][r]; 70 int newl = newr - (r-l+1-cnt) + 1; 71 return query(mid+1,R,newl,newr,dep+1,k-cnt); 72 } 73 } 74 int main() 75 { 76 int T; 77 int n; 78 scanf("%d",&T); 79 int iCase = 0; 80 while(T--) 81 { 82 iCase++; 83 scanf("%d",&n); 84 memset(tree,0,sizeof(tree)); 85 memset(sum,0,sizeof(sum)); 86 for(int i = 1;i <= n;i++) 87 { 88 scanf("%d",&tree[0][i]); 89 sorted[i] = tree[0][i]; 90 } 91 sort(sorted+1,sorted+n+1); 92 build(1,n,0); 93 printf("Case #%d:\n",iCase); 94 int m,l,r; 95 scanf("%d",&m); 96 while(m--) 97 { 98 scanf("%d%d",&l,&r); 99 l++;r++; 100 ans = 0; 101 int tmp = query(1,n,l,r,0,(l+r)/2-l+1); 102 if((l+r)%2)ans-=tmp; 103 printf("%I64d\n",ans); 104 } 105 printf("\n"); 106 } 107 return 0; 108 }