POJ 2104 第K大的数, 主席树,

第一次接触这种神奇的数据结构,感觉不错。有学了个好东西,也不难。他主要应该是针对于数据统计的,例如本题的第k大的数。算法的主要思想是 先对给定的数离散化,然后在线段树中保存数字出现的次数(即叶子节点会存该节点所对应的数字出现的次数,非叶结点则保存子节点的数字之和)(这就与我们普通的线段树不同了)。然后我们会对于 从 a1 到 ai ( 1<=i<=n )之间的数据建一棵线段树,因此总共会建n+1棵,(看到这,你会不会担心MLE呢?其实不会的,因为节点是可以共用的)。 建完后,如果 查询是针对 ai 到 aj 这个区间的,那么我们就可以用aj那棵线段树上的值减去 ai-1 那棵线段树上的值,那么就可以得到在这个区间中各个数字出现的次数。加油!

真奇怪,为什么 POJ 上写read(),读入优化反而慢了700多毫秒。求大神赐教。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define rep(i,j,k) for(int i = j; i <= k; i++)
 5 using namespace std;
 6 int root[100005], a[100005], p[100005];
 7 int n_nodes = 0, n_numb;
 8
 9 struct node{
10 int times, lc, rc;
11 } nod[3000000];
12
13 void build(int l,int r,int&p){
14     p = ++n_nodes;
15     nod[p].lc = nod[p].rc = nod[p].times = 0;
16     if( l >= r ) return;
17     int mid = (l+r)/2;
18     build(l,mid,nod[p].lc); build(mid+1,r,nod[p].rc);
19 }
20
21 void build2(int l,int r,int&p, int pre,int mre)
22 {
23     p = ++n_nodes;
24     nod[p] = nod[pre];
25     nod[p].times++;
26     if( l >= r ) return;
27     int mid = (l+r)/2;
28     if( mre <= mid ){
29         build2(l,mid,nod[p].lc,nod[pre].lc,mre);
30     }
31     else {
32         build2(mid+1,r,nod[p].rc,nod[pre].rc,mre);
33     }
34 }
35
36 int ask(int l,int r,int pre,int p,int k)
37 {
38     if( l >= r ) return l;
39     int s = nod[nod[p].lc].times - nod[nod[pre].lc].times;
40     int mid = (l+r) / 2;
41     if( s >= k ){
42         return ask(l,mid,nod[pre].lc,nod[p].lc,k);
43     }
44     else {
45         return ask(mid+1,r,nod[pre].rc,nod[p].rc,k-s);
46     }
47 }
48
49 int main()
50 {
51     int n, q;
52     scanf("%d %d",&n,&q);
53     rep(i,1,n){
54         scanf("%d", &a[i]);
55         p[i] = a[i];
56     }
57     sort(p+1,p+1+n);
58     n_numb = unique(p+1,p+1+n) - p - 1;
59     build(1,n_numb,root[0]);
60     rep(i,1,n){
61         int m = lower_bound(p+1,p+n_numb+1,a[i]) - p;
62         build2(1,n_numb,root[i],root[i-1],m);
63     }
64     rep(i,1,q){
65         int x, y, k;
66         scanf("%d %d %d",&x,&y,&k);
67         int m = ask(1,n_numb,root[x-1],root[y],k);
68         printf("%d\n", p[m]);
69     }
70     return 0;
71 }
时间: 2024-09-29 23:36:17

POJ 2104 第K大的数, 主席树,的相关文章

POJ 2104&amp;HDU 2665 Kth number(主席树入门+离散化)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

COGS 930. [河南省队2012] 找第k小的数 主席树

主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 #define MAX 2000005 using namespace std; int sum[MAX],l[MAX],mid[MAX],r[MAX],a[MAXN],b[MAXN],n,m,sz,size,root[MAXN],cnt; void build(int &x,int z,int y

poj 2401 划分树 求区间第k大的数

题目:http://poj.org/problem?id=2104 划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,, 模板题: 贴代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR(a) memset(a,0,sizeof(a)) const int MAXN = 1000

51nod p1175 区间中第K大的数

1175 区间中第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 一个长度为N的整数序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有数中,第K大的数是多少. 例如: 1 7 6 3 1.i = 1, j = 3,k = 2,对应的数为7 6 3,第2大的数为6. Input 第1行:1个数N,表示序列的长度.(2 <= N <= 50000) 第2 - N + 1行:每行1个数,对应序列中的元素.(0 <= S[i] <

找出第k大的数

编程题#3:找出第k大的数 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 用户输入N和K,然后接着输入N个正整数(无序的),程序在不对N个整数排序的情况下,找出第K大的数.注意,第K大的数意味着从大到小排在第K位的数. 输入 N K a1 a2 a3 a4 ..... aN 输出 b 样例输入 5 2 32 3 12 5 89 样例输出 32 提示 这是一道很经典的算法问

51 nod 1105 第K大的数

1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * B[0],A[0] * B[1] ......A[1] * B[0],A[1] * B[1]......A[n - 1] * B[n - 1](数组A同数组B的组合).求数组C中第K大的数. 例如:A:1 2 3,B:2 3 4.A与B组合成的C包括2 3 4 4 6 8 6 9 12共9个数. I

统计前k大的数x

我终于敲上了题目--记起来啦! 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000. 第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000. 第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1 2 3 0 5 样例输出 9 8 7 6 5 //AC自动机x #include<iostream&

找出整数中第k大的数

一  问题描述: 找出m个整数中第k(0<k<m+1)大的整数. 二  举例: 假设有12个整数:data[1, 4, -1, -4, 9, 8, 0, 3, -8, 11, 2, -9],请找出第5大的数(容易知道是0). 三   算法思路:        一种基于快排思想的算法可以在O(n)复杂度内找到第k大的数,首先要知道partition这个函数,它可以调整一个序列 使小于key的元素都排在key左边,大于key的元素都排在key右边,key可以在这个序列中任意选择,一般选择给定序 列

《数据结构与算法分析:C语言描述》读书笔记------练习1.1 求第K大的数

求一组N个数中的第k个最大者,设k=N/2. 1 import java.util.Random; 2 3 4 public class K_Max { 5 6 /** 7 * @param args 8 */ 9 //求第K大的数,保证K大于等于1,小于等于array.length/2哦 10 public static int TopK(int array[],int K) 11 { 12 int topk[] = new int [K]; 13 for(int i = 0; i<topk.