[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题;

对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便;如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引;若要求第k大,建树时反向排序即可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<cmath>
 8 using namespace std;
 9 const int maxn=1e5+10;
10 int root[maxn];
11 struct node{
12     int l,r,sum;
13 }p[maxn*20];
14 int cnt=0;
15 //建树从1开始建
16 //rt是当前节点在p数组中的坐标
17 int build(int l,int r){
18     int rt=++cnt;
19     p[rt].sum=0;
20     p[rt].l=p[rt].r=0;
21     if(l==r) return rt;
22     int mid=(l+r)>>1;
23     p[rt].l=build(l,mid);
24     p[rt].r=build(mid+1,r);
25     return rt;
26 }//开始先建一棵空树,其实可以动态开点,就是各节点均为0
27 int update(int l,int r,int c,int k){//update更新的是索引
28     int nc=++cnt;
29     p[nc]=p[c];
30     p[nc].sum++;
31     int mid=(l+r)>>1;
32     if(l==r) return nc;
33     if(mid>=k) p[nc].l=update(l,mid,p[c].l,k);
34     else p[nc].r=update(mid+1,r,p[c].r,k);
35     return nc;
36 }
37
38 int query(int l,int r,int x,int y,int k){
39     if(l==r) return l;
40     int mid=(l+r)>>1;
41     int sum=p[p[y].l].sum-p[p[x].l].sum;
42     if(sum>=k) return query(l,mid,p[x].l,p[y].l,k);
43     else return query(mid+1,r,p[x].r,p[y].r,k-sum);
44 }
45 vector<int>v;
46 int a[maxn];
47 int getid(int x){
48     return int(lower_bound(v.begin(),v.end(),x)-v.begin())+1;
49 }
50 int main(){
51     ios::sync_with_stdio(0);
52     cin.tie(0);
53     cout.tie(0);
54     int n,m;
55     cin>>n>>m;
56     for(int i=1;i<=n;i++){
57         cin>>a[i];
58         v.push_back(a[i]);
59     }
60     sort(v.begin(),v.end());
61     v.erase(unique(v.begin(), v.end()),v.end());
62     //建树过程很重要
63     root[0]=build(1,n);//一定注意更新root数组
64     for(int i=1;i<=n;i++){
65         root[i]=update(1,n,root[i-1],getid(a[i]));//update是更新某个数出现次数的
66     }
67     int c,d,q;
68     for(int i=0;i<m;i++){
69         cin>>c>>d>>q;
70         int ans=query(1,n,root[c-1],root[d],q);
71         cout<<v[ans-1]<<endl;
72     }
73     return 0;
74 }
时间: 2024-10-25 18:51:03

[poj2104]可持久化线段树入门题(主席树)的相关文章

【刷题】洛谷 P3834 【模板】可持久化线段树 1(主席树)

题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个正整数,表示这个序列各项的数字. 接下来M行每行包含三个整数l, r, kl,r,k , 表示查询区间[l, r][l,r] 内的第k小值. 输出格式: 输出包含k行,每行1个正整数,依次表示每一次查询的

【模板】可持久化线段树 1(主席树)

题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个正整数,表示这个序列各项的数字. 接下来M行每行包含三个整数l,r,k l, r, kl,r,k , 表示查询区间[l,r][l, r][l,r]内的第k小值. 输出格式: 输出包含k行,每行1个正整数,

可持久化线段树 1(主席树模板)

[模板]可持久化线段树 1(主席树)(luogu) (本人的模板) Description 题目背景 这是个非常经典的主席树入门题——静态区间第 kk 小数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定 nn 个整数构成的序列,将对于指定的闭区间查询其区间内的第 kk 小值. 输入格式 第一行包含两个正整数 n,mn,m,分别表示序列的长度和查询的个数.第二行包含 nn 个整数,表示这个序列各项的数字.接下来 mm 行每行包含三个整数 l, r, kl,r,k , 表示查询

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【Luogu】P3384主席树模板(主席树查询K小数)

YEAH!我也是一个AC主席树模板的人了! 其实是个半吊子 我将尽量详细的讲出我的想法. 主席树太难,我们先搞普通线段树好了 普通线段树怎么做?我的想法是查询K次最小值,每次查完把查的数改成INF,查完再改回来... MDZZ 于是就有了主席树. 先不考虑主席树,我们来考虑一个奇特的线段树. 一般的线段树,数列位置是下标,而把数列维护值作为线段树中存的元素. 那我们如果反过来,把数列元素当做线段树的下标...??? 比如说数列[4 2 3 1] 如果线段树的下标是1.2.3.4......? 那

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间 [l,r]中妹子们美丽度的逆序对数吗?" 蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线." 请你帮助一下Autumn吧.

hdu 5919 主席树入门题

主席树是从右往左初始化,每次把这个数出现过的位置消去,然后在当前位置加一. 然后我的做法是查两遍,第一遍能找出不同的个数,除一半:再用这个值查,一直到底,最后返回位置,比较套路的一题. #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include &l

poj2104求区间第k小,静态主席树入门模板

看了很久的主席树,最后看https://blog.csdn.net/williamsun0122/article/details/77871278这篇终于看懂了 #include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]为原