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 }
2015/7/4

 

你可能感兴趣的:(HDU)