主席树(一种可持久化线段树)

study from:

静态主席树:https://blog.csdn.net/a1351937368/article/details/78884526

动态主席树:https://blog.csdn.net/WilliamSun0122/article/details/77885781

静态:

https://www.luogu.org/problemnew/show/P3834

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <time.h>
  6 #include <string>
  7 #include <set>
  8 #include <map>
  9 #include <list>
 10 #include <stack>
 11 #include <queue>
 12 #include <vector>
 13 #include <bitset>
 14 #include <ext/rope>
 15 #include <algorithm>
 16 #include <iostream>
 17 using namespace std;
 18 #define ll long long
 19 #define minv 1e-6
 20 #define inf 1e9
 21 #define pi 3.1415926536
 22 #define nl 2.7182818284
 23 const ll mod=1e9+7;//998244353
 24 const int maxn=2e5+10;
 25
 26 struct rec
 27 {
 28     int a,b;
 29 }f[maxn];
 30
 31 struct node
 32 {
 33     int l,r,sum,number;
 34 }tr[maxn*20];
 35
 36 int a[maxn],_index=0,value,tnum=0,result;
 37 int be[maxn],v[maxn];
 38
 39 int cmp(rec a,rec b)
 40 {
 41     return a.a<b.a;
 42 }
 43
 44 void ini_build(int l,int r)
 45 {
 46     tr[_index].sum=0;
 47     if (l==r)
 48     {
 49         tr[_index].l=0;
 50         tr[_index].r=0;
 51         tr[_index].number=++tnum;
 52     }
 53     else
 54     {
 55         int m=(l+r)>>1,cur=_index;
 56         tr[cur].l=++_index;
 57         ini_build(l,m);
 58
 59         tr[cur].r=++_index;
 60         ini_build(m+1,r);
 61     }
 62 }
 63
 64 void build(int l,int r,int pos)
 65 {
 66     if (l==r)
 67     {
 68         tr[_index].l=0;
 69         tr[_index].r=0;
 70         tr[_index].sum=tr[pos].sum+1;   ///not 1
 71         tr[_index].number=tr[pos].number;
 72     }
 73     else
 74     {
 75         int m=(l+r)>>1,cur=_index;
 76         tr[cur].sum=tr[pos].sum+1;
 77         if (value<=m)
 78         {
 79             tr[cur].l=++_index;
 80             tr[cur].r=tr[pos].r;
 81             build(l,m,tr[pos].l);
 82         }
 83         else
 84         {
 85             tr[cur].l=tr[pos].l;
 86             tr[cur].r=++_index;
 87             build(m+1,r,tr[pos].r);
 88         }
 89         tr[cur].sum=tr[tr[cur].l].sum+tr[tr[cur].r].sum;
 90     }
 91 }
 92
 93 void query(int _indexl,int _indexr,int z)
 94 {
 95     if (tr[_indexl].l==0)
 96     {
 97         result=tr[_indexl].number;
 98         return;
 99     }
100     if (tr[tr[_indexr].l].sum-tr[tr[_indexl].l].sum>=z)
101         query(tr[_indexl].l,tr[_indexr].l,z);
102     else
103         query(tr[_indexl].r,tr[_indexr].r,z-tr[tr[_indexr].l].sum+tr[tr[_indexl].l].sum);
104 }
105
106 int main()
107 {
108     int n,m,i,num,x,y,z;
109     scanf("%d%d",&n,&m);
110     for (i=1;i<=n;i++)
111     {
112         scanf("%d",&f[i].a);
113         f[i].b=i;
114     }
115     sort(f+1,f+n+1,cmp);
116     num=0;
117     f[0].a=2e9;
118     for (i=1;i<=n;i++)
119     {
120         if (f[i].a!=f[i-1].a)
121         {
122             num++;
123             v[num]=f[i].a;
124         }
125         a[f[i].b]=num;
126     }
127     be[0]=++_index;
128     ini_build(1,num);
129     for (i=1;i<=n;i++)
130     {
131         be[i]=++_index;
132         value=a[i];
133         build(1,num,be[i-1]);
134     }
135
136     while (m--)
137     {
138         scanf("%d%d%d",&x,&y,&z);
139         query(be[x-1],be[y],z);
140         printf("%d\n",v[result],m);
141     }
142     return 0;
143 }
144 /*
145 5 100
146 1 5 1 5 5
147 1 5 2
148 1 5 3
149 */

原文地址:https://www.cnblogs.com/cmyg/p/9607334.html

时间: 2024-11-13 06:36:48

主席树(一种可持久化线段树)的相关文章

【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

[BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一天,她准备去探访他.对着窗外的阳光,临行前她再次弹起了琴.她的琴的发声十分特殊.让我们给一个形式化的定义吧.所有的 n 个音符形成一棵由音符 C ( 1 号节点) 构成的有根树,每一个音符有一个音高 Hi .Arietta 有 m 个力度,第 i 个力度能弹出 Di 节点的子树中,音高在 [Li,R

[GDOI2016] 疯狂动物园 [树链剖分+可持久化线段树]

题面 太长了,而且解释的不清楚,我来给个简化版的题意: 给定一棵$n$个点的数,每个点有点权,你需要实现以下$m$个操作 操作1,把$x$到$y$的路径上的所有点的权值都加上$delta$,并且更新一个版本 操作2,对于有向路径$(x,y)$上的点$a_i$,求下面的和值: $\sum_{i=1}^{len} a_i \sum_{j=1}^{len-i} j$ 操作3,回到第$i$个版本(但是下一次更新以后还是到总版本号+1的那个版本) 思路 这个题显然一眼就是树剖+可持久化数据结构啊 那么核心

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队

看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: 1 #include<bits/stdc++.h> 2 #define ll long long 3 #define uint unsigned int 4 #define ull unsigned long long 5 #define inf 4294967295 6 #define N 100005 7 #define M 100005 8 #

BZOJ 2588 Count on a tree (COT) 可持久化线段树

题目大意:查询树上两点之间的第k大的点权. 思路:树套树,其实是正常的树套一个可持久化线段树.因为利用权值线段树可以求区间第k大,然后再应用可持久化线段树的思想,可以做到区间减法.详见代码. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define NIL (tree[0]) using name

归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k大 ,,,, 这个问题的通用算法是 划分树,, 说白一点就是把快速排序的中间结果存起来, 举个栗子 原数列 4 1 8 2 6 9 5 3 7 sorted 1 2 3 4 5 6 7 8 9 ........................... qs[0] 4 1 8 2 6 9 5 3 7 q

主席树/函数式线段树/可持久化线段树

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

[可持久化线段树(主席树)]

主席树 抛出问题 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个整数,表示这个序列各项的数字. 接下来M行每行包含三个整数l, r, kl,r,k , 表示查询区间[l, r][l,r]内的第k小值. 输出格式: 输出包含k行,每行1个整数,依次表示每一次查询的结果 解决问题 主席树(可持久化线段树)法 于是针对这个问题,新的数据结构诞生了,也就是主席树. 主席树本名

主席树(可持久化线段树) 静态第k大

可持久化数据结构介绍 可持久化数据结构是保存数据结构修改的每一个历史版本,新版本与旧版本相比,修改了某个区域,但是大多数的区域是没有改变的, 所以可以将新版本相对于旧版本未修改的区域指向旧版本的该区域,这样就节省了大量的空间,使得可持久化数据结构的实现成为了可能. 如下图,就是可持久化链表 插入前 插入后 尽可能利用历史版本和当前版本的相同区域来减少空间的开销. 而主席树(可持久化线段树)的原理同样是这样. 有n个数字,  我们将其离散化,那么总有[1,n]个值,如果建一棵线段树,每个结点维护子