[Luogu2617] Dynamic Rankings [树状数组套线段树] [单点修改&区间kth]

[ L i n k \frak{Link} Link]


板子题不多说了。
如果感觉看了半天网上题解看不懂的话,我建议:罚你重抄树状数组

联动:<Click Here> 带插入区间 kth


树状数组套线段树

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cctype>
using namespace std;
#define lowbit(x) (x&-x)
const int MAXN = 200005;
const int MAXS = 300 * MAXN;
int n, m, tot = 0, a[MAXN], t[MAXN], RtOri[MAXN], RtMod[MAXN], LC[MAXS], RC[MAXS], Seg[MAXS];
int ListBas[MAXN], ListSub[MAXN];
struct SM
{
    bool t;
    int a, b, c;
    SM(bool aa=0, int bb=0, int cc=0, int dd=0)
    {
        t = aa;
        a = bb;
        b = cc;
        c = dd;
    }
}o[MAXN];
void Init()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    a[0] = n;
    char typ;
    for (int ori, tar, kth, i = 1; i <= m; ++i)
    {
        scanf(" %c %d%d", &typ, &ori, &tar);
        if (typ == 'Q')
        {
            scanf("%d", &kth);
            o[i] = SM(0, ori, tar, kth);
        }
        else
        {
            o[i] = SM(1, ori, tar, 0);
            a[++n] = tar;
        }
    }
    memcpy(t, a, sizeof(a));
    sort(t + 1, t + 1 + n);
    t[0] = unique(t + 1, t + 1 + n) - t - 1;
    n = a[0];
    for (int i = 1; i <= n; ++i) a[i] = lower_bound(t + 1, t + 1 + t[0], a[i]) - t;
    for (int i = 1; i <= m; ++i) if (o[i].t) o[i].b = lower_bound(t + 1, t + 1 + t[0], o[i].b) - t;
}
void SegIns_Ini(int &Pos, int Pre, int L, int R, int Tar)
{
    LC[Pos = ++tot] = LC[Pre], RC[Pos] = RC[Pre], Seg[Pos] = Seg[Pre] + 1;
    if (L == R) return;
    int Mid = L + R >> 1;
    if (Tar <= Mid) 
    {
        SegIns_Ini(LC[Pos], LC[Pre], L, Mid, Tar);
        return;
    }
    SegIns_Ini(RC[Pos], RC[Pre], Mid + 1, R, Tar);
}
void SegIns_Mod(int &Pos, int L, int R, int Tar, int Val)
{
    Seg[Pos ? Pos : (Pos = ++tot)] += Val;
    if (L == R) return;
    int Mid = L + R >> 1;
    if (Tar <= Mid) 
    {
        SegIns_Mod(LC[Pos], L, Mid, Tar, Val);
        return;
    }
    SegIns_Mod(RC[Pos], Mid + 1, R, Tar, Val);
}
int GetSize()
{
    int SumBas = 0, SumSub = 0;
    for (int i = 1; i <= ListBas[0]; ++i) SumBas += Seg[LC[ListBas[i]]];
    for (int i = 1; i <= ListSub[0]; ++i) SumSub += Seg[LC[ListSub[i]]];
    return SumBas - SumSub;
}
int SegQuery(int L, int R, int qL, int qR, int Kth)
{
    if (L == R) return L;
    int LeftSize = GetSize() + Seg[LC[qR]] - Seg[LC[qL]];
    int Mid = L + R >> 1;
    if (Kth <= LeftSize)
    {
        for (int i = 1; i <= ListBas[0]; ++i) ListBas[i] = LC[ListBas[i]];
        for (int i = 1; i <= ListSub[0]; ++i) ListSub[i] = LC[ListSub[i]];
        return SegQuery(L, Mid, LC[qL], LC[qR], Kth);
    }
    for (int i = 1; i <= ListBas[0]; ++i) ListBas[i] = RC[ListBas[i]];
    for (int i = 1; i <= ListSub[0]; ++i) ListSub[i] = RC[ListSub[i]];
    return SegQuery(Mid + 1, R, RC[qL], RC[qR], Kth - LeftSize);
}
int Query(int L, int R, int Kth)
{
    ListBas[0] = ListSub[0] = 0;
    for (int i = R; i; i -= lowbit(i)) ListBas[++ListBas[0]] = RtMod[i];
    for (int i = L - 1; i; i -= lowbit(i)) ListSub[++ListSub[0]] = RtMod[i];
    return SegQuery(1, t[0], RtOri[L-1], RtOri[R], Kth);
}
void Mod(int Pos, int Val)
{
    for (int i = Pos; i <= n; i += lowbit(i)) SegIns_Mod(RtMod[i], 1, t[0], a[Pos], Val);
}
void SegIniZero(int &Pos, int L, int R)
{
    Pos = ++tot;
    if (L == R) return;
    int Mid = L + R >> 1;
    SegIniZero(LC[Pos], L, Mid);
    SegIniZero(RC[Pos], Mid + 1, R);
}
void SegInit()
{
    SegIniZero(RtOri[0], 1, t[0]);
    for (int i = 1; i <= n; ++i) SegIns_Ini(RtOri[i], RtOri[i-1], 1, t[0], a[i]);
}
void SegWork()
{
    for (int i = 1; i <= m; ++i)
    {
        if (!o[i].t)
        {
            printf("%d\n", t[Query(o[i].a, o[i].b, o[i].c)]);
            continue;
        }
        Mod(o[i].a, -1);
        a[o[i].a] = o[i].b;
        Mod(o[i].a, +1);
    }
}
void Main()
{
    SegInit();
    SegWork();
}
int main()
{
    Init();
    Main();
    return 0;
}

整体二分 / 树状数组套平衡树

什么?
我先鸽为敬.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值