算法的学习没有尽头!前面还有无尽远的路!

  前两天做一道题的时候看到划分树,找到小航航大牛的博客看了一下,很神奇的算法,总的来说就是一个逆归并的过程,从大到小的归并排序,建立线段树,记录每个区间中被分到左子树的数据,然后查询的时候就可以用log(n)的时间查询任意区间第K大数了。由于本人缺乏创新性,代码严重抄袭小航航牛,不再赘述!

  回头用划分树做了北大的2104和杭电的3473,速度还算可以,这里仅给出3473的代码以供参考!

 

代码
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4  #define M 100005
5  struct Node{
6 int l,r;
7 } Tree[M*4];
8 int sorted[M],toleft[20][M],val[20][M];
9 __int64 sum[M],tolsum[20][M];
10 __int64 lsum,rsum;
11 int cmp(const void *a,const void *b)
12 { return *(int *)a - *(int *)b; }
13 void build(int l,int r,int d,int idx)
14 {
15 Tree[idx].l = l; Tree[idx].r = r;
16 if (l == r) return;
17 int i,mid = (l+r)>>1,midv = sorted[mid];
18 int lsame = mid - l + 1;
19 for (i = l; i <= r; i++) if (val[d][i] < midv) lsame--;
20 int lpos = l, rpos = mid+1, same = 0;
21 for (i = l; i <= r; i++){
22 if (i == l){
23 toleft[d][i] = 0; tolsum[d][i] = 0;
24 }
25 else{
26 toleft[d][i] = toleft[d][i-1]; tolsum[d][i] = tolsum[d][i-1];
27 }
28 if (val[d][i] < midv){
29 toleft[d][i]++; val[d+1][lpos++] = val[d][i];
30 tolsum[d][i] += val[d][i];
31 }
32 else if (val[d][i] > midv) val[d+1][rpos++] = val[d][i];
33 else {
34 if (same < lsame){
35 same++; toleft[d][i]++; val[d+1][lpos++] = val[d][i];
36 tolsum[d][i] += val[d][i];
37 }
38 else val[d+1][rpos++] = val[d][i];
39 }
40 }
41 build(l,mid,d+1,idx<<1);
42 build(mid+1,r,d+1,(idx<<1) + 1);
43 }
44 int query(int l,int r,int k,int d,int idx)
45 {
46 if (l == r) return val[d][l];
47 int tol;
48 int stol;
49 __int64 cntl;
50 if (l == Tree[idx].l){
51 stol = 0; tol = toleft[d][r];
52 cntl = 0;
53 } else{
54 stol = toleft[d][l-1]; tol = toleft[d][r] - stol;
55 cntl = tolsum[d][l-1];
56 }
57 if (tol >= k){
58 int start = Tree[idx].l + stol, end = start + tol -1;
59
60 return query(start,end,k,d+1,idx<<1);
61 }else {
62 lsum += tolsum[d][r] - cntl;
63 int mid = (Tree[idx].l + Tree[idx].r)>>1;
64 int tor = r - l - tol + 1;
65 int stor = l - Tree[idx].l - stol;
66 return query(mid+1+stor,mid+stor+tor,k-tol,d+1,(idx<<1)+1);
67 }
68 }
69 int main()
70 {
71 int ncase,cas,i,k,n,m;
72 scanf ("%d",&ncase);
73 for (cas = 1; cas <= ncase; cas++){
74 sum[0] = 0;
75 scanf ("%d",&n);
76 for (i = 1; i<= n; i++){
77 scanf ("%d",&val[0][i]);
78 sorted[i] = val[0][i];
79 sum[i] = sum[i-1] + sorted[i];
80 }
81 qsort(sorted+1,n,sizeof(sorted[0]),cmp);
82 build(1,n,0,1);
83 scanf ("%d",&m);
84 printf ("Case #%d:\n",cas);
85 for (i = 0; i< m; i++){
86 int s,e;
87 scanf ("%d%d",&s,&e);
88 s++; e++;
89 int num = e-s+1;
90 k = num/2; if (num % 2 != 0) k++;
91 lsum = 0;
92 rsum = sum[e] - sum[s-1];
93 int ans = query(s,e,k,0,1);
94 rsum -= ans; rsum -= lsum;
95 __int64 re = (__int64)(k-1)*(__int64)ans - lsum + rsum - (__int64)(num - k)*(__int64)ans;
96 printf ("%I64d\n",re);
97 }
98 printf ("\n");
99 }
100 return 0;
101 }

 

  dp和联通分量,下一阶段的目标,路漫漫谁与我同行,水长长自有人同舟!

posted on 2010-08-24 21:27  looker  阅读(266)  评论(0编辑  收藏  举报