替罪羊树求条,玄关
查看原帖
替罪羊树求条,玄关
895690
gghack_Nythix楼主2025/1/15 10:42

rt,贺的 oi wiki 的

# include <bits/stdc++.h>
# define int long long
# define rank charafrisk
using namespace std;
const double alpha = 0.7;
const int N = 1e5 + 5;
int nodecnt , root , w[N] , lc[N] , rc[N] , wn[N] , s[N] , sz[N] , sd[N] , n;
//节点个数
//,根
//,权值
//,左右儿子
//,某权值出现次数(wn[k]表示k号节点的元素出现几次)
//,子树大小(每个重复元素算1次)
//,子树大小(每个重复元素算wn[k]次)
//,考虑删除操作的子树大小。
int reb[N];
void calc (int now) {
    s[now] = s[lc[now]] + s[rc[now]] + 1;
    sz[now] = sz[lc[now]] + sz[rc[now]] + wn[now];
    sd[now] = sd[lc[now]] + sd[rc[now]] + (wn[now] != 0);
}
bool CRebuild (int now) { 
return wn[now] && (alpha * s[now] <= (double)max(s[lc[now]] , s[rc[now]]) 
|| (double)sd[now] <= alpha * s[now] ); }
void Reb_zk (int &cnt , int now) {
    if (!now) return ;
    Reb_zk (cnt , lc[now]);
    if (wn[now]) reb[++cnt] = now;
    Reb_zk (cnt , rc[now]);
}//展开
int Reb_build (int l , int r) {
    int mid = l + r >> 1;
    if (l >= r) return 0;
    lc[reb[mid]] = Reb_build (l , mid);
    rc[reb[mid]] = Reb_build (mid + 1 , r);
    calc (reb[mid]);
    return reb[mid];
}
void rebuild (int &now) {
    int cnt = 0;
    Reb_zk (cnt , now);
    now = Reb_build (1 , cnt + 1); // 我他妈rebuild少建立一个节点
}
void Ins (int &now , int val) {
    if (!now) {
        now = ++nodecnt;
        if (!root) root = 1;
        w[now] = val , lc[now] = rc[now] = 0;
        wn[now] = sz[now] = s[now] = sd[now] = 1;
    }
    else {
        if (w[now] == val) wn[now] ++;
        else if (w[now] < val) Ins (rc[now] , val);
        else Ins (lc[now] , val);
        calc (now);
        if ( CRebuild(now) ) rebuild (now);
    }
}
void Del (int & now , int val) {
    if (!now) return ;
    if (w[now] == val) if (wn[now]) -- wn[now];
    else {
        if (w[now] < val) Del (rc[now] , val);
        else Del(lc[now] , val);
    }
    calc (now);
    if ( CRebuild(now) ) rebuild (now);
}
int qry_rankpre (int now , int val) { //查有几个数比他小,就是查权值严格小于某值的最大名次
    if (!now) return 0;
    else if (w[now] == val && wn[now]) return sz[lc[now]];
    else if (w[now] < val) return qry_rankpre (rc[now] , val) + sz[lc[now]] + wn[now];
    else return qry_rankpre (lc[now] , val);
}
int qry_ranknxt (int now , int val) { //和上面的反着来,权值严格大于某值的最小名次。
    if (!now) return 1;
    if (w[now] == val && wn[now]) return sz[lc[now]];
    else if (val < w[now]) return qry_ranknxt (lc[now] , val);
    else return qry_ranknxt (rc[now] , val) + sz[lc[now]] + wn[now];
}
int qry_rankval (int now , int rk) {//查某个排名的数
    if (!now) return 0;
    else if (sz[lc[now]] < rk && rk <= sz[lc[now]] + wn[now]) return w[now];
    else if (sz[lc[now]] + wn[now] < rk) return qry_rankval (rc[now] , rk - sz[lc[now]] - wn[now]);
    else return  qry_rankval (lc[now] , rk);
}
int Fdpre (int now , int val) { return qry_rankval (now , qry_rankpre(now , val)  ); }
int Fdnxt (int now , int val) { return qry_rankval (now , qry_ranknxt(now , val)  ); }
signed main () {
    cin >> n;
    while ( n -- ) {
        int opt , x;
        cin >> opt >> x;
        if (opt == 1) Ins (root , x);
        if (opt == 2) Del (root , x);
        if (opt == 3) cout << qry_rankpre (root , x) + 1 << "\n" ;
        if (opt == 4) cout << qry_rankval (root , x) << "\n";
        if (opt == 5) cout << Fdpre (root , x) << "\n";
        if (opt == 6) cout << Fdnxt (root , x) << "\n";
    }
    return 0;
}
2025/1/15 10:42
加载中...