首页 > 其他分享 >主席树

主席树

时间:2023-05-16 21:11:55浏览次数:29  
标签:rt sz lc int ls rc 主席

主席树

权值树

在正常的树中,我们用下标来指元素(显然)
但,我们也可以用值指元素,显然的,不能开\(4\times10^9\),于是,只能考虑动态建树

主席树

主席树,有黄嘉泰同志发明,因其缩写为时任主席的名字,故曰主席树

主席树是一种可持久优化的树,意思是,它保存历史信息(不忘初心)
或曰,主席树如何可持久化\

有线段树A,现在右子树增一结点,新线段树B如图
image
我们发现B的左子树未改变,因此对树略修改
image
是的,我们让B的左子树指向A的左子树,这样,我们只要为右子树增开少量空间即可
让我们在C点继续开结点,画面越发诡异
image

结论,增加结点增且仅增加根到此结点路径上的结点,总复杂度是\(\Omicron(\log10^9)\)

在加新节点时,不断比较与旧的差别,有就修改,不然就保持原样(连着原来的点)

以下是部分代码实现

#define lc(rt) t[rt].ls
#define rc(rt) t[rt].rs
#define sz(rt) t[rt].sz
void up(int rt)
{
    sz(rt) = sz(lc(rt)) + sz(rc(rt));
}
void ins(int &rt, int ls, int l, int r, int v)
//这里使用“引用”,使得下面对rt的修改会覆盖原本值
{
    t[rt = ++tot] = t[ls];
    if (l == r)
        sz(rt)++;
    else
    {
        if (v <= mid)
            ins(lc(rt), lc(ls), l, mid, v);
        else
            ins(rc(rt), rc(ls), mid + 1, r, v);
        up(rt);
    }
}

接下来,我们要面对的问题即是如何求第k小的值
我们把\([L,R]\)区间看做在树R与树L-1间新增的结点,首先比较左边新增的个数,若大于k,显然,要找的数在左边

int x = sz(lc(rt2)) - sz(lc(rt));
if (x >= k)
    return que(lc(rt), lc(rt2), l, mid, k);

不然就在右边

else
    return que(rc(rt), rc(rt2), mid + 1, r, k - x);

代码就是这样罢

int que(int rt,int ls, int l, int r, int k)
{
    if (l == r)
        return l;//权值树,l就是值
    int x = sz(lc(rt)) - sz(lc(ls));
    if (x >= k)
        return que(lc(ls), lc(rt), l, mid, k);
    else
        return que(rc(ls), rc(rt), mid + 1, r, k - x);
}

以下是全code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define lc(rt) t[rt].ls
#define rc(rt) t[rt].rs
#define sz(rt) t[rt].sz
#define all 1, INF
using namespace std;
const int N = 5e5, M = N * 30, INF = 1e9;
struct node{int ls, rs, sz;} t[M];int n, m, tot, rt[N];
void up(int rt){sz(rt) = sz(lc(rt)) + sz(rc(rt));}
void ins(int &rt, int ls, int l, int r, int v)
//ls表上一个树
{
    t[rt = ++tot] = t[ls];
    if (l == r) sz(rt)++;
    else
    {
        if (v <= mid) ins(lc(rt), lc(ls), l, mid, v);
        else ins(rc(rt), rc(ls), mid + 1, r, v);
        up(rt);
    }
}
int que(int rt,int ls, int l, int r, int k)
//rt表L,rt2表R
{
    if (l == r) return l;//权值树,l就是值
    int x = sz(lc(rt)) - sz(lc(ls));
    if (x >= k)return que(lc(rt), lc(ls), l, mid, k);
    else return que(rc(rt), rc(ls), mid + 1, r, k - x);
}
int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1, x; i <= n; i++) scanf("%d", &x), ins(rt[i], rt[i - 1], all, x);
    for (int i = 1, a, b, c; i <= m; i++) 
        scanf("%d %d %d", &a, &b, &c), printf("%d\n", que(rt[b], rt[a - 1], all, c));
    return 0;
}

标签:rt,sz,lc,int,ls,rc,主席
From: https://www.cnblogs.com/ssj233/p/17406813.html

相关文章

  • 主席树
    可持久化线段树值域线段树设线段树节点\(i\)管辖区间\([l,r]\),\(i\)的\(val\)表示$l\ge$且$\ler$的数的个数那么\(i.l\)表示$l\ge$且$\lemid$的数的个数,\(i.r\)表示$mid+1\ge$且$\ler$的数的个数如果建\(n\)棵值域线段树,第\(i\)棵......
  • WWW‘23 | Apr 30-May 4,交叉新兴领域顶级会议!清华唐杰任大会主席!
     WWW,曾用名为TheInternationalConferenceofWorldWideWeb,从2018年开始更名为Thewebconference。WWW为交叉,新兴,综合领域的顶级会议,CCFA类,CoreConferenceRankingA*类会议,H5指数80,ImpactScore14.69。会议的目的是为全世界的互联网领域研究人员提供一个学术交流平台,共同......
  • 主席树 学习笔记
    考试的时候用到了,顺便学习一下。upd:2023.04.21终于把坑填了。0x00前言主席树(又称可持久化线段树,函数式线段树)是一种常用的数据结构。它以保存每次修改时的历史版本为主要思想,拥有大量的应用场景(可持久化trie/并查集/数组\(\ldots\))(当然,常数也是很大的)。0x01引入例题:HDU2......
  • 主席树学习笔记
    主席树,又名可持久化线段树,可以访问多个历史版本的树上存的信息。图及其他来源于此:https://www.cnblogs.com/hyfhaha/p/10678275.html基本思想用到的基本思想就是对于每一个修改版本的树,只新建修改后的节点,如果是每一个版本新开一个线段树的话空间一定不够。这是普通的线段树......
  • 可持久化线段树(主席树)
              代码#include<bits/stdc++.h>usingnamespacestd;constintN=4e7+10;intn,m,t,top,rt,mode,x,y;intf[N],a[N],root[N];structkkk{intl,r,val;}tree[N];intclone(intnode){top++;tree[top]=tree[node];return......
  • Codeforces Round 368 (Div. 2) D. Persistent Bookcase 主席树维护bitset
    在学主席树时找到了这道题本来yyyy了一个二维的主席树这种东西,然后发现很多信息好像维护不了观察到n和m都很小,考虑把一整行看成一个节点,开一个bitset然后区间取反、单点......
  • Codeforces Round 406 (Div. 1) C. Till I Collapse 主席树上二分
    首先贪心是显然的,但是询问有n个先考虑一个朴素的主席树做法对于每个k,对于当前固定的L,二分R,用主席树查询一下[L,R]区间内的不同数个数是否大于K个(主席树的经典应用),更新......
  • 【YBT2023寒假Day12 A】我的世界(二分)(主席树)
    我的世界题目链接:YBT2023寒假Day12A题目大意有n个数,每一秒每个数都会减小1,而且你可以选一个数让它减小x,小于0的数会变成0。给你s秒,问你s秒操作后所有数中......
  • 主席树
    有时间再修P3919【模板】可持久化线段树1(可持久化数组)点击查看代码#include<bits/stdc++.h>#defineintlonglong#definecsconst#defineilinline#defineri......
  • 【代码源 Div1 - 108】#464. 数数(主席树,区间比k小的数的个数)HDU4417
    problemsolution主席树查询区间比k小的数的个数建树之后直接在目标区间的主席树内将H作为挡板递归计数。#include<bits/stdc++.h>usingnamespacestd;#defineIOSios::s......