(模板)Luogu3380-2B平衡树

Problem

传送门

一个长度为n的序列,支持一堆操作,大致操作如下:

1.k在区间的排名(由小到大)2.区间第k小;3.单点修改;4&5:k的在区间上的前驱/后继。

Solution

右边大佬说树套树很简单,就是两个基本操作套起来即可。

然后我码了一个半小时才码完。

(模板)Luogu3380-2B平衡树

虽然话没说错,树状数组套主席树……

但是这代码……

算了,还是太菜了……

2,3操作:

其实做法比较好理解,树状数组具有前缀性,主席树也是利用前缀

所以可以将树状数组的每一个节点上建一颗主席树

这样就可以完美的实现修改操作了

具体实现……就是把原本的树状数组一般操作改为主席树上的修改操作

询问的时候将树状数组上\(lowbit\)到的点全部带进去主席树里去询问就可以了。

以上是第2,3操作(搞了半天才完成2,3操作)

1操作:

考虑线段树的遍历过程

如果当前权值线段树的\(mid\)大于当前询问的权值k,那么我们会走向左儿子,否则往走向右儿子

而且,当我们走向右儿子时k一定大于左边的所有数

所以我们只要在此时加左子树的数的个数即可

4,5操作:

既然知道了任意数在区间里的\(rank\)前驱和后继就很好处理了

\(k\)前驱只需要查\(k\)在区间里的\(rank\),区间排名为\(rank - 1\)的数即为所求

\(k\)的后继则需要知道\(k\)在区间中的\(rank\)与\(k\)在区间中出现的次数\(num\),再求区间中排名为\(rank+num\)的数即可。

放一份奇丑的代码,以后再改。

Code

#include <bits/stdc++.h>

using namespace std;

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define fst first
#define snd second

template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

inline int read(){
    int res = 0, fl = 1;
    char r = getchar();
    for (; !isdigit(r); r = getchar()) if(r == '-') fl = -1;
    for (; isdigit(r); r = getchar()) res = (res << 3) + (res << 1) + r - 48;
    return res * fl;
}
typedef long long LL;
typedef pair<int, int> pii;
const int Maxn = 4e5 + 10;

struct CMtree{
    int ls, rs, sum;
}tre[Maxn << 7];
struct SGT{
    int ch[20],siz;
    SGT(){ siz = 0;}
    SGT Ls(){
        SGT B;
        for (int i = 1; i <= siz; ++i) B.ch[i] = tre[ch[i]].ls;
        B.siz = siz;
        return B;
    }
    SGT Rs(){
        SGT B;
        for (int i = 1; i <= siz; ++i) B.ch[i] = tre[ch[i]].rs;
        B.siz = siz;
        return B;
    }
    int sum(){
        int num = 0;
        for (int i = 1; i <= siz; ++i) num += tre[ch[i]].sum;
        return num;
    }
};
int A[Maxn], n, m, cnt, root[Maxn << 6];
int INF = 1e8 + 10;
pii operator + (const pii a, const pii b){
    return mp(a.fst + b.fst, a.snd + b.snd);
}
namespace CMT{
    inline void modify(int &rt,int l, int r, int pos, int v){
        if(!rt) rt = ++cnt;
        tre[rt].sum += v;
        if(l == r) return;
        int mid = l + r >> 1;
        if(mid >= pos) modify(tre[rt].ls, l, mid, pos, v);
        else modify(tre[rt].rs, mid + 1, r, pos, v);
    }
    inline void build(int &rt, int grt,int l, int r, int pos){
        tre[rt = ++cnt] = tre[grt];
        tre[rt].sum++;
        if(l == r) return;
        int mid = l + r >> 1;
        if(mid >= pos) build(tre[rt].ls, tre[grt].ls, l, mid, pos);
        else build(tre[rt].rs, tre[grt].rs, mid + 1, r, pos);
    }
    inline int Query(SGT a, SGT b, int l, int r, int k){
        if(l == r) return l;
        int mid = l + r >> 1, t = b.Ls().sum() - a.Ls().sum();
        //printf("%d %d %d %d\n", l, r, t, k);
        if(k <= t) return Query(a.Ls(), b.Ls(), l, mid, k);
        else return Query(a.Rs(), b.Rs(), mid + 1, r, k - t);
    }
    inline pii rank(SGT a, SGT b,int l,int r, int k){
        if(l == r) {
            return mp(1,b.sum() - a.sum());
        }
        int mid = l + r >> 1;
        if(k <= mid) return rank(a.Ls(), b.Ls(), l, mid, k);
        else return mp(b.Ls().sum() - a.Ls().sum(), 0) + rank(a.Rs(), b.Rs(), mid + 1, r, k);
    }
}
namespace BIT{
    int lst[Maxn];
    inline int lowbit(int x) {return x & -x;}
    inline void change(int pos,int a, int b){
        for (; pos <= n; pos += lowbit(pos))
            CMT :: modify(root[pos], 1,INF, a, -1), CMT :: modify(root[pos], 1,INF, b, 1);
    }
    inline void add(int pos,int a){
        for (; pos <= n; pos += lowbit(pos)){
            CMT :: build(root[pos], lst[pos], 1, INF, a), lst[pos] = root[pos];
        }
    }
    inline pii Query(int l, int r, int k, bool fl){
        SGT a, b;
        for (int i = l - 1; i > 0; i -= lowbit(i)) a.ch[++a.siz] = root[i];
        for (int i = r; i > 0; i -= lowbit(i)) b.ch[++b.siz] = root[i];
        if(fl) return mp(CMT :: Query(a, b, 1, INF, k), 0);
        else return CMT :: rank(a, b, 1, INF, k);
    }
}
void Front(int l, int r, int k) {
    pii Rank = BIT::Query(l, r, k, 0);
    if(Rank.fst == 1) printf("-2147483647\n");
    else printf("%d\n",BIT::Query(l, r, Rank.fst - 1, 1).fst);
}
void Next(int l, int r, int k){
    pii Rank = BIT::Query(l, r, k, 0);
    int all = r - l + 1;
    if(Rank.fst + Rank.snd > all) printf("2147483647\n");
    else printf("%d\n",BIT::Query(l, r, Rank.fst + Rank.snd, 1).fst);
}
int main()
{
    n = read(), m = read();
    for (int i = 1; i <= n; ++i) A[i] = read(), BIT::add(i, A[i]);
    while(m--){
        int opt = read();
        if(opt == 3) {int pos = read(), k = read(); BIT::change(pos,A[pos],k); A[pos] = k; continue;}
        int l = read(), r = read(), k = read();
        if(opt == 1) printf("%d\n",BIT::Query(l, r, k, 0).fst);
        if(opt == 2) printf("%d\n",BIT::Query(l, r, k, 1).fst);
        if(opt == 4) Front(l, r, k);
        if(opt == 5) Next(l, r, k);
    }
    return 0;
}

上一篇:[luogu]P1852


下一篇:安振平老师的5895号不等式问题的证明