首页 > 其他分享 >主席树

主席树

时间:2022-11-03 21:22:58浏览次数:60  
标签:cur val int tree ++ MAXN 主席

传送门

点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;

typedef long long ll;
const int MAXN = 2e5 + 10;
int n, m, cnt = 0;  //cnt代表当前的节点编号,这里用到了动态开点的思想
int a[MAXN], b[MAXN], re[MAXN], head[MAXN];    //原数组, b和re数组mp反映射数组, 每个历史版本的线段树的头节点
map<int, int> mp;   //离散化
struct Node
{
    int l, r, val, lson, rson;  //l, r权值区间内有多少个数val,当前节点的左儿子,当前节点的右儿子
} tree[MAXN * 30];  //主席树一般开30,不够再往上10倍开

void build(int l, int r, int cur)
{
    tree[cur].l = l, tree[cur].r = r, tree[cur].val = 0;
    if (l == r)
        return;
    tree[cur].lson = ++cnt; tree[cur].rson = ++cnt; //动态开点的思想
    int mid = l + r >> 1;
    build(l, mid, tree[cur].lson), build(mid + 1, r, tree[cur].rson);
}

void pushup(int cur)
{
    tree[cur].val = tree[tree[cur].lson].val + tree[tree[cur].rson].val;
    return;
}

void update(int tar, int cur, int pre)  //要更新的点建立一棵在前一个版本的基础上建立一棵新树
{
    tree[cur].l = tree[pre].l, tree[cur].r = tree[pre].r, tree[cur].val = tree[pre].val;    //肯定在前一个版本的基础上,所以先初始化
    if (tree[cur].l == tree[cur].r) //准确的到那个数了,就对那个数的权值区间个数++
    {
        tree[cur].val++;
        return;
    }
    int mid = tree[cur].l + tree[cur].r >> 1;
    if (tar <= mid) //说明要更新的点在左子树
    {
        tree[cur].lson = ++cnt; //动态开点左子树
        tree[cur].rson = tree[pre].rson;    //右侧的节点不变
        update(tar, tree[cur].lson, tree[pre].lson);    //继续更新左子树
    }
    else    //说明要更新的点在右子树
    {
        tree[cur].lson = tree[pre].lson;    //左侧的节点不变
        tree[cur].rson = ++cnt; //动态开点右子树
        update(tar, tree[cur].rson, tree[pre].rson);    //继续更新有子树
    }
    pushup(cur);
}

int query(int k, int cur, int pre)
{
    if (tree[cur].l == tree[cur].r) //当前左右区间相等,必然就是这个区间里面第k小的数
        return tree[cur].l;
    int val = tree[tree[cur].lson].val - tree[tree[pre].lson].val;
    if (k <= val)   //说明这个第k小在左子树
        return query(k, tree[cur].lson, tree[pre].lson);
    else    //说明这个第k小的在右子树
        return query(k - val, tree[cur].rson, tree[pre].rson);  //因为左子树已经有val个了,所以这里要先减去val个    
}

int main()
{
    IOS; cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> a[i], mp[a[i]] = 1;
    int pos = 0;
    for (auto it = mp.begin(); it != mp.end(); ++it)    //离散化处理
        it->second = ++pos, re[pos] = it->first;
    for (int i = 1; i <= n; ++i)
        b[i] = mp[a[i]];
    head[0] = 1, cnt = 1;
    build(1, mp.size(), head[0]);   //先建立一棵空树
    for (int i = 1; i <= n; ++i)
    {
        head[i] = ++cnt;    //每一个数对应每一个更新版本,每一个更新版本对应一个cnt, 代表这个版本的头
        update(mp[a[i]], head[i], head[i - 1]);
    }
    int l, r, k;
    while (m--)
    {
        cin >> l >> r >> k;
        cout << re[query(k, head[r], head[l - 1])] << endl; //第r个版本和l - 1个历史版本进行计算
    }
    return 0;
}

标签:cur,val,int,tree,++,MAXN,主席
From: https://www.cnblogs.com/jumo-xiao/p/16855870.html

相关文章

  • 【SA+启发式合并+主席树】P7361拜神
    题目链接由于自己感觉写不明白,先来写题解学习自Alex_wei题意给定长为\(n\leq5\times10^4\)字符串,\(q\leq10^5\)次询问,每次询问\([l,r]\)子串内出现两次以上......
  • 可持久化线段树-主席树
    求第k小数#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;constintM=1e4+10;vector<int>nums;intn,m;inta[N];introot[N];intidx;struc......
  • 可持久化线段树 主席树 详解
    ......
  • Tower Defense (分块+差分的差分+优化空间方法, 主席树做法待补)
    题目大意:   思路:这题难点在于每一秒会恢复值而且(mi+ri,ci)有一个阈值. 发现一个点被清理后,他的恢复有3个状态,一次恢复ri的值,当t<ci/ri,恢复ci%ri......
  • 主席树-----动态开点,不hash
    ​​POJ-2104 ​​第k大#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<vector>#include<iostream>#include<algorithm>usingname......
  • HDU4417 Super Mario (主席树)
    主席树另一模板。查询的是[L,R]中<=h的个数。1#include<bits/stdc++.h>2usingnamespacestd;3#definelctr[i].ch[0]4#definerctr[i].ch[1]5#define......
  • 【luogu P7518】宝石(主席树)(二分)
    宝石题目链接:luoguP7518题目大意给你一棵树,树上每个点有颜色,然后给你一个颜色序列,保证序列上没有一样的颜色。然后多次操作每次问你树上的一条路径,要你找到一个最大的......
  • 主席树讲解
    概念可以看作是可持久化权值线段树可持久化又可以分为部分可持久化和完全可持久化部分可持久化————所有版本都可以访问,但是只有最新版本可以修改完全可持久化——......
  • 额额额~主席树
    题意:给定一个长度为n的序列和一个正整数m,有若干个询问,每次询问一个区间[l,r],请问区间是否存在k个数的和>=m。写的时候:没注意到是不用连续的k个数,用前缀和写样例过了,但......
  • P3963 [TJOI2013] 奖学金——主席树
    最后翻看题解才发现可以不用主席树……就当是练习好了基本思路本题要让中位数最大,如果是最小值最大我们可以用二分答案,二中位数最大可不可以呢?显然是不行的,所以我们枚举......