POJ 2104 K-th Number

这个题以前就做过了,用归并树+二分,2000+ms水过了。今天整理资料,zhk提到了划分树,于是去试了一下,经过几次小小的错误,最终过掉了,900+ms。时间效率很高,O(mlogn),是区间查询第k大值的利器。

该总结的东西基本上都写在注释里面了,就不再废话了。

 

ExpandedBlockStart.gif POJ 2104 K-th Number(划分树)
 1  // 从源序列开始,首先用buffer将此序列排序。
 2  // 每次划分的时候按照中点值将元素按照大小分别排在左子树和右子树,相当于一个排序的过程,用数组val记录。
 3  // 在划分的时候用数组toLeft记录每次划分时被分到左子树的元素的数目。
 4 
 5  #include  < stdio.h >
 6  #include  < string .h >
 7  #include  < algorithm >
 8 
 9  const   int  MaxN  =   100010 ;
10  int  val[ 20 ][MaxN], toLeft[ 20 ][MaxN];
11  int  srt[MaxN];
12  int  M, N;
13 
14  struct  Node {
15       int  l, r;
16  }node[MaxN << 3 ];
17 
18  inline  int  L( int  x) { return  (x << 1 ) + 1 ;}
19  inline  int  R( int  x) { return  (x << 1 ) + 2 ;}
20 
21  void  build_tree( int  s,  int  e,  int  cur_row,  int  id) {
22      node[id].l  =  s; node[id].r  =  e;
23       if (s  ==  e)
24           return ;
25       int  mid  =  (s + e) >> 1 ;
26       int  emN  =  mid  +   1   -  s;
27       for ( int  i  =  s; i  <=  e;  ++ i) {         // 记录与中位数相同的元素被分到左子树的数目。
28           if (val[cur_row][i]  <  srt[mid])     // 因为这些元素有可能被分到左子树,也有可能被分到右子树。
29              emN -- ;                         // 记录这个值便于后面的操作。
30      }
31       int  lp  =  s, rp  =  mid + 1 ;
32       for ( int  i  =  s; i  <=  e;  ++ i) {         // 计算被划分到左子树的元素个数。
33          toLeft[cur_row][i]  =  i != s ? toLeft[cur_row][i - 1 ]: 0 ;
34           if (val[cur_row][i]  <  srt[mid]) {
35              val[cur_row + 1 ][lp ++ =  val[cur_row][i];
36              toLeft[cur_row][i] ++ ;
37          }
38           else   if (val[cur_row][i]  >  srt[mid])
39              val[cur_row + 1 ][rp ++ =  val[cur_row][i];
40           else   if (emN) {                     // 当emN计数为0时,划分到左子树的中位数元素划分完毕。
41              val[cur_row + 1 ][lp ++ =  val[cur_row][i];
42              toLeft[cur_row][i] ++ ;
43              emN -- ;
44          }
45           else
46              val[cur_row + 1 ][rp ++ =  val[cur_row][i];
47      }
48      build_tree(s, mid, cur_row  +   1 , L(id));             // 递归建树。
49      build_tree(mid + 1 , e, cur_row  +   1 , R(id));
50  }
51 
52  // {[left part][query interval][right part]}        此为树的一个节点
53  // {[(LL)(RL)][(LI)(RI)][right part]}        
54  //         LL:划分到左子树的左边部分;    RL:划分到右子树的左边部分
55  //         LI:划分到左子树的中间部分;    RL:划分到右子树的中间部分
56  // 根据以上信息判断在哪个子树进行查询,并且重新计算query interval, 递归查询即可。
57 
58  int  query( int  s,  int  e,  int  k,  int  cur_row,  int  id) {
59       if (s  ==  e)                    
60           return  val[cur_row][s];
61       int  LL  =  s == node[id].l ? 0 :toLeft[cur_row][s - 1 ];     // 计算LL, LI
62       int  LI  =  toLeft[cur_row][e]  -  LL;
63       if (k  <=  LI)
64           return  query(node[id].l + LL, node[id].l + LL + LI - 1 , k, cur_row + 1 , L(id));
65       int  mid  =  (node[id].l  +  node[id].r)  >>   1 ;
66       int  RL  =  s  -  node[id].l  -  LL;                     // 计算RL, RI
67       int  RI  =  e  +   1   -  s  -  LI;
68       return  query(mid + 1 + RL, mid + 1 + RL + RI - 1 , k  -  LI, cur_row + 1 , R(id)); 
69  }
70 
71  int  main() {
72       while (scanf( " %d%d " & N,  & M)  ==   2 ) {
73           for ( int  i  =   0 ; i  <  N;  ++ i) {
74              scanf( " %d " , srt + i);
75              val[ 0 ][i]  =  srt[i];
76          }
77          std::sort(srt, srt  +  N);
78          build_tree( 0 , N - 1 0 0 );
79           int  s, e, k;
80           for ( int  i  =   0 ; i  <  M;  ++ i) {
81              scanf( " %d%d%d " & s,  & e,  & k);
82              printf( " %d\n " , query(s - 1 , e - 1 , k,  0 0 ));
83          }
84      }
85       return   0 ;
86  }
87 

 

 

ExpandedBlockStart.gif POJ 2104 K-th Number(归并+二分)
 1  #include  < stdio.h >
 2  #include  < string .h >
 3  #include  < algorithm >
 4 
 5  using   namespace  std;
 6 
 7  inline  int  MID( int  s,  int  e) { return  (s + e) >> 1 ;}
 8 
 9  const   int  MaxN  =   100010 ;
10  int  merge_tree[ 20 ][MaxN], n, m, dep[MaxN];
11  int  u, v, k, flag;
12 
13  void  Merge( int  begin,  int  end,  int  d) {
14       if (begin  +   1   ==  end) {
15          merge_tree[d][begin]  =  merge_tree[ 0 ][begin];
16          dep[begin]  =  d; 
17           return ;
18      }
19       int  Mid  =  MID(begin, end);
20      Merge(begin, Mid, d  +   1 );
21      Merge(Mid, end, d  +   1 );
22       int  i, j, k;
23       for (i  =  begin, j  =  Mid, k  =  begin; i  !=  Mid  &&  j  !=  end;) {
24           if (merge_tree[d + 1 ][i]  <  merge_tree[d + 1 ][j])
25              merge_tree[d][k ++ =  merge_tree[d + 1 ][i ++ ];
26           else
27              merge_tree[d][k ++ =  merge_tree[d + 1 ][j ++ ];
28      }
29       if (i  !=  Mid) {
30           for (; i  !=  Mid;  ++ i) merge_tree[d][k ++ =  merge_tree[d + 1 ][i];
31      }
32       if (j  !=  end) {
33           for (; j  !=  end;  ++ j) merge_tree[d][k ++ =  merge_tree[d + 1 ][j];
34      }
35  }
36 
37  int  search( int  begin,  int  end,  int  s,  int  e,  int  x,  int  d) {
38       int  Mid;
39       if (s  ==  begin  &&  end  ==  e) {
40           if (x  >  merge_tree[d][end - 1 ])
41               return  end  -  begin;
42           if (x  <  merge_tree[d][begin])
43               return   0 ;
44           int  u  =  begin  -   1 , v  =  end;
45           while (u + 1   <  v) {
46              Mid  =  MID(u, v);
47               if (merge_tree[d][Mid]  <=  x) {
48                   if (merge_tree[d][Mid]  ==  x)
49                      flag ++ ;
50                  u  =  Mid;
51              }
52               else
53                  v  =  Mid;
54          }
55           return  u  -  begin  +   1 ;
56      }
57      Mid  =  MID(begin, end);
58       if (s  >=  Mid)
59           return  search(Mid, end, s, e, x, d + 1 );
60       if (e  <=  Mid)
61           return  search(begin, Mid, s, e, x, d + 1 );
62       return  search(begin, Mid, s, Mid, x, d + 1 +  search(Mid, end, Mid, e, x, d + 1 );
63  }
64 
65  void  work() {
66       int  begin  =   - 1 , end  =  n, Mid;
67       while (begin  +   1   <  end) {
68          Mid  =  MID(begin, end);
69          flag  =   0 ;
70           int  sum  =  search( 0 , n, u, v + 1 , merge_tree[ 0 ][Mid],  0 );
71           if (flag  &&  sum  -  flag  <  k  &&  sum  >=  k) {
72              printf( " %d\n " , merge_tree[ 0 ][Mid]);
73               return ;
74          }
75           else   if (sum  <  k)
76              begin  =  Mid;
77           else
78              end  =  Mid;
79      }
80  }
81 
82  int  main() {
83       while (scanf( " %d%d " & n,  & m)  !=  EOF) {
84           for ( int  i  =   0 ; i  <  n;  ++ i) scanf( " %d " , merge_tree[ 0 +  i);
85          Merge( 0 , n,  0 );
86           for ( int  i  =   0 ; i  <  m;  ++ i) {
87              scanf( " %d%d%d " & u,  & v,  & k);
88              u -- ; v -- ;
89              work();
90          }
91      }
92       return   0 ;
93  }
94 

 

 

转载于:https://www.cnblogs.com/destinydesigner/archive/2010/12/05/1896959.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值