各种模板

· · 个人记录

板子大集

快读 和 快写

inline void read(int &x){//快读
    int f = 1;
    x = 0;
    char s = getchar();
    while(s < '0' || s > '9') {
        if(s == '-') f = -1;
        s = getchar();
    }
    while(s >= '0' && s <= '9') {
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

inline void write(int x){//快写
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
    return ;
}

基础算法

高精度(感谢丁神的高精板子)

#include <bits/stdc++.h>
using namespace std;
namespace CommonlyIO {
typedef long long ll;
typedef pair<int, int> PII;
#define x first
#define y second
#define sz(a) a.size()
#define lowbit(x) (x & -x)
#define debug(x) cout << #x << ':' << x << endl
#define VI vector<int>
#define all(a) a.begin(), a.end()
#define rep(i, c, n) for (int i = c; i <= n; ++i)
#define per(i, c, n) for (int i = c; i >= n; --i)
#define w(x) while (x--)
#define db double
#define pb(x) push_back(x)
#define gc() getchar()
}  // namespace CommonlyIO
using namespace CommonlyIO;
struct uinT : public vector<int> {
    const static int mod = (int)1e7;
    const static int wei = 7;
    uinT() {}
    uinT(int t) : vector<int>(1, t) {}
    uinT(vector<char> s) {
        for (int i = s.size() - 1; i >= 0; i -= wei) {
            int t = 0;
            for (int j = max(0, i - wei + 1); j <= i; ++j) {
                t = (t * 10 + (s[j] - '0'));
            }
            push_back(t);
        }
    }
    int const& operator[](const int n) const {
        return (n < size()) ? *(cbegin() + n) : (int const&)0;
    }
    int& operator[](const int n) { return *(begin() + n); }
    friend void input(uinT& a) {
        vector<char> s;
        char c = gc();
        while (!isdigit(c))
            c = gc();
        while (isdigit(c))
            s.push_back(c), c = gc();
        a = uinT(s);
    }
    friend void output(const uinT& a) {
        printf("%d", a.back());
        for (int i = a.size() - 2; i >= 0; --i) {
            printf("%0*d", wei, a[i]);
        }
    }
    friend bool operator==(uinT const& a, uinT const& b) {
        if (a.size() != b.size())
            return 0;
        for (int i = 0; i < a.size(); ++i)
            if (a[i] != b[i])
                return 0;
        return 1;
    }
    friend bool operator!=(uinT const& a, uinT const& b) { return !(a == b); }
    friend bool operator<(uinT const& a, uinT const& b) {
        if (a.size() != b.size())
            return a.size() < b.size();
        for (int i = a.size() - 1; i >= 0; --i) {
            if (a[i] != b[i])
                return a[i] < b[i];
        }
        return 0;
    }
    friend bool operator>(uinT const& a, uinT const& b) { return b < a; }
    friend bool operator<=(uinT const& a, uinT const& b) {
        if (a.size() != b.size())
            return a.size() < b.size();
        for (int i = a.size() - 1; i >= 0; --i) {
            if (a[i] != b[i])
                return a[i] < b[i];
        }
        return 1;
    }
    friend bool operator>=(uinT const& a, uinT const& b) { return b <= a; }
    friend uinT operator+(uinT const& a, uinT const& b) {
        uinT c = a;
        c.resize(max(a.size(), b.size()) + 1);
        for (int i = 0; i < b.size(); ++i) {
            c[i] += b[i];
            if (c[i] >= mod) {
                c[i] -= mod;
                c[i + 1] += 1;
            }
        }
        for (int i = b.size(); i < c.size() - 1; ++i) {
            if (c[i] >= mod) {
                c[i] -= mod;
                c[i + 1] += 1;
            }
        }
        if (c.back() == 0)
            c.pop_back();
        return c;
    }
    friend uinT operator-(uinT const& a, uinT const& b) {
        uinT c = a;
        for (int i = 0; i < b.size(); ++i) {
            c[i] -= b[i];
            if (c[i] < 0) {
                c[i] += mod;
                c[i + 1] -= 1;
            }
        }
        for (int i = b.size(); i < c.size(); ++i) {
            if (c[i] < 0) {
                c[i] += mod;
                c[i + 1] -= 1;
            } else
                break;
        }
        while (c.size() > 1 && c.back() == 0)
            c.pop_back();
        return c;
    }
    friend uinT operator*(uinT const& a, uinT const& b) {
        if (a == 0 || b == 0)
            return 0;  //!
        vector<ll> t(a.size() + b.size());
        for (int i = 0; i < a.size(); ++i) {
            for (int j = 0; j < b.size(); ++j) {
                t[i + j] += 1ll * a[i] * b[j];
            }
        }
        for (int i = 0; i < t.size() - 1; ++i) {
            t[i + 1] += t[i] / mod;
            t[i] %= mod;
        }
        if (t.back() == 0)
            t.pop_back();
        uinT c;
        c.resize(t.size());
        for (int i = 0; i < t.size(); ++i) {
            c[i] = (int)t[i];
        }
        return c;
    }
    friend uinT operator/(uinT const& a, uinT const& b) {
        if (a.size() < b.size())
            return 0;
        uinT c, d;
        c.assign(a.end() - b.size() + 1, a.end());
        for (int i = a.size() - b.size(); i >= 0; --i) {
            c.insert(c.begin(), a[i]);
            ll t = (c.size() > b.size())
                       ? (1ll * c.back() * mod + *(c.crbegin() + 1))
                       : (c.back());
            int l = (t / (b.back() + 1));
            int r = ((t + 1) / b.back());
            while (l < r) {
                int mid = (l + r + 1) >> 1;
                if (b * mid <= c)
                    l = mid;
                else
                    r = mid - 1;
            }
            c -= b * l;
            if (c.back() == 0)
                c.pop_back();
            d.push_back(l);
        }
        reverse(d.begin(), d.end());
        if (d.size() > 1 && d.back() == 0)
            d.pop_back();
        return d;
    }
    friend uinT operator%(uinT const& a, uinT const& b) {
        return a - a / b * b;
    }
    friend uinT const& operator+=(uinT& a, uinT const& b) { return a = a + b; }
    friend uinT const& operator-=(uinT& a, uinT const& b) { return a = a - b; }
    friend uinT const& operator*=(uinT& a, uinT const& b) { return a = a * b; }
    friend uinT const& operator/=(uinT& a, uinT const& b) { return a = a / b; }
    friend uinT const& operator%=(uinT& a, uinT const& b) { return a = a % b; }
};

struct bigint {
    bool f;
    uinT t;
    bigint() : f(0) {}
    bigint(int t) : f(t < 0), t(uinT(abs(t))) {}
    bigint(bool f, uinT t) : f(f), t(t) {}
    friend void input(bigint& a) {
        a.f = 0;
        vector<char> s;
        char c = gc();
        for (; !isdigit(c); c = gc())
            if (c == '-')
                a.f = 1;
        while (isdigit(c))
            s.push_back(c), c = gc();
        a.t = uinT(s);
    }
    friend void output(const bigint& a) {
        if (a.f)
            putchar('-');
        output(a.t);
    }
    friend bigint abs(bigint const& a) { return bigint(0, a.t); }
    friend bool operator==(bigint const& a, bigint const& b) {
        return (a.f == b.f) && (a.t == b.t);
    }
    friend bool operator!=(bigint const& a, bigint const& b) {
        return !(a == b);
    }
    friend bool operator<(bigint const& a, bigint const& b) {
        if (a.f != b.f)
            return a.f;
        return a.f ? a.t > b.t : a.t < b.t;
    }
    friend bool operator>(bigint const& a, bigint const& b) { return b < a; }
    friend bool operator<=(bigint const& a, bigint const& b) {
        if (a.f != b.f)
            return a.f;
        return a.f ? a.t >= b.t : a.t <= b.t;
    }
    friend bool operator>=(bigint const& a, bigint const& b) { return b <= a; }
    friend bigint operator-(bigint const& a) { return bigint(!a.f, a.t); }
    friend bigint operator+(bigint const& a, bigint const& b) {
        if (a.f == b.f)
            return bigint(a.f, a.t + b.t);
        else if (a.t > b.t)
            return bigint(a.f, a.t - b.t);
        else if (a.t < b.t)
            return bigint(b.f, b.t - a.t);
        else
            return 0;
    }
    friend bigint operator-(bigint const& a, bigint const& b) {
        if (a.f == b.f) {
            if (a.t > b.t)
                return bigint(a.f, a.t - b.t);
            else if (a.t < b.t)
                return bigint(!a.f, b.t - a.t);
            else
                return 0;
        } else
            return bigint(a.f, a.t + b.t);
    }
    friend bigint operator*(bigint const& a, bigint const& b) {
        if (a == 0 || b == 0)
            return 0;
        return bigint(a.f ^ b.f, a.t * b.t);
    }
    friend bigint operator/(bigint const& a, bigint const& b) {
        return bigint(a.f ^ b.f, a.t / b.t);
    }
    friend bigint operator%(bigint const& a, bigint const& b) {
        return bigint(a.f, a.t % b.t);
    }
    friend bigint const& operator+=(bigint& a, bigint const& b) {
        return a = a + b;
    }
    friend bigint const& operator-=(bigint& a, bigint const& b) {
        return a = a - b;
    }
    friend bigint const& operator*=(bigint& a, bigint const& b) {
        return a = a * b;
    }
    friend bigint const& operator/=(bigint& a, bigint const& b) {
        return a = a / b;
    }
    friend bigint const& operator%=(bigint& a, bigint const& b) {
        return a = a % b;
    }
};
const int INF = 0x3f3f3f3f;
const ll INFll = 9223372036854775807;
const double PI = 3.1415926;
#define getchar()                                                          \
    (tt == ss && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) \
         ? EOF                                                             \
         : *ss++)
char In[1 << 20], *ss = In, *tt = In;
namespace Fastio {
struct Reader {
    template <typename T>
    Reader& operator>>(T& x) {
        x = 0;
        short f = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                f *= -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9')
            x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        x *= f;
        return *this;
    }
    Reader& operator>>(double& x) {
        x = 0;
        double t = 0;
        short f = 1, s = 0;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '.') {
            if (c == '-')
                f *= -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9' && c != '.')
            x = x * 10 + (c ^ 48), c = getchar();
        if (c == '.')
            c = getchar();
        else {
            x *= f;
            return *this;
        }
        while (c >= '0' && c <= '9')
            t = t * 10 + (c ^ 48), s++, c = getchar();
        while (s--)
            t /= 10.0;
        x = (x + t) * f;
        return *this;
    }
    Reader& operator>>(long double& x) {
        x = 0;
        long double t = 0;
        short f = 1, s = 0;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '.') {
            if (c == '-')
                f *= -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9' && c != '.')
            x = x * 10 + (c ^ 48), c = getchar();
        if (c == '.')
            c = getchar();
        else {
            x *= f;
            return *this;
        }
        while (c >= '0' && c <= '9')
            t = t * 10 + (c ^ 48), s++, c = getchar();
        while (s--)
            t /= 10.0;
        x = (x + t) * f;
        return *this;
    }
    Reader& operator>>(char& c) {
        c = getchar();
        while (c == ' ' || c == '\n' || c == '\r')
            c = getchar();
        return *this;
    }
    Reader& operator>>(char* str) {
        int len = 0;
        char c = getchar();
        while (c == ' ' || c == '\n' || c == '\r')
            c = getchar();
        while (c != ' ' && c != '\n' && c != '\r')
            str[len++] = c, c = getchar();
        str[len] = '\0';
        return *this;
    }
    Reader& operator>>(string& str) {
        str.clear();
        char c = getchar();
        while (c == ' ' || c == '\n' || c == '\r')
            c = getchar();
        while (c != ' ' && c != '\n' && c != '\r')
            str.push_back(c), c = getchar();
        return *this;
    }
    Reader& operator>>(bigint& a) {
        input(a);
        return *this;
    }
    Reader& operator>>(__float128& x) {
        x = 0;
        __float128 t = 0;
        short f = 1, s = 0;
        char c = getchar();
        while ((c < '0' || c > '9') && c != '.') {
            if (c == '-')
                f *= -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9' && c != '.')
            x = x * 10 + (c ^ 48), c = getchar();
        if (c == '.')
            c = getchar();
        else {
            x *= f;
            return *this;
        }
        while (c >= '0' && c <= '9')
            t = t * 10 + (c ^ 48), s++, c = getchar();
        while (s--)
            t /= 10.0;
        x = (x + t) * f;
        return *this;
    }
    Reader() {}
} cin;
const char endl = '\n';
struct Writer {
    const int Setprecision = 6;
    typedef int mxdouble;
    template <typename T>
    Writer& operator<<(T x) {
        if (x == 0) {
            putchar('0');
            return *this;
        }
        if (x < 0)
            putchar('-'), x = -x;
        static short sta[40];
        short top = 0;
        while (x > 0)
            sta[++top] = x % 10, x /= 10;
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        return *this;
    }
    Writer& operator<<(const bigint& n) {
        output(n);
        return *this;
    }
    Writer& operator<<(__float128 x) {
        if (x < 0)
            putchar('-'), x = -x;
        mxdouble _ = x;
        x -= (__float128)_;
        static short sta[40];
        short top = 0;
        while (_ > 0)
            sta[++top] = _ % 10, _ /= 10;
        if (top == 0)
            putchar('0');
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        putchar('.');
        for (int i = 0; i < Setprecision; i++)
            x *= 10;
        _ = x;
        while (_ > 0)
            sta[++top] = _ % 10, _ /= 10;
        for (int i = 0; i < Setprecision - top; i++)
            putchar('0');
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        return *this;
    }
    Writer& operator<<(double x) {
        if (x < 0)
            putchar('-'), x = -x;
        mxdouble _ = x;
        x -= (double)_;
        static short sta[40];
        short top = 0;
        while (_ > 0)
            sta[++top] = _ % 10, _ /= 10;
        if (top == 0)
            putchar('0');
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        putchar('.');
        for (int i = 0; i < Setprecision; i++)
            x *= 10;
        _ = x;
        while (_ > 0)
            sta[++top] = _ % 10, _ /= 10;
        for (int i = 0; i < Setprecision - top; i++)
            putchar('0');
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        return *this;
    }
    Writer& operator<<(long double x) {
        if (x < 0)
            putchar('-'), x = -x;
        mxdouble _ = x;
        x -= (long double)_;
        static short sta[40];
        short top = 0;
        while (_ > 0)
            sta[++top] = _ % 10, _ /= 10;
        if (top == 0)
            putchar('0');
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        putchar('.');
        for (int i = 0; i < Setprecision; i++)
            x *= 10;
        _ = x;
        while (_ > 0)
            sta[++top] = _ % 10, _ /= 10;
        for (int i = 0; i < Setprecision - top; i++)
            putchar('0');
        while (top > 0)
            putchar(sta[top] + '0'), top--;
        return *this;
    }
    Writer& operator<<(char c) {
        putchar(c);
        return *this;
    }
    Writer& operator<<(char* str) {
        int cur = 0;
        while (str[cur])
            putchar(str[cur++]);
        return *this;
    }
    Writer& operator<<(const char* str) {
        int cur = 0;
        while (str[cur])
            putchar(str[cur++]);
        return *this;
    }
    Writer& operator<<(string str) {
        int st = 0, ed = str.size();
        while (st < ed)
            putchar(str[st++]);
        return *this;
    }
    Writer() {}
} cout;
}  // namespace Fastio
using namespace Fastio;
#define cin Fastio::cin
#define cout Fastio::cout
#define endl Fastio::endl
#define __int128 bigint

矩阵(取模)

int mod = ;//模数自己设
struct Matrix{
    int n,m;
    int a[205][205];

    inline void init(){ memset(a,0,sizeof a); }
    inline void init_I(){
        init();
        F(i,1,min(n,m)) a[i][i]=1;
    }

    inline friend void operator = (Matrix &a,Matrix b){
        a.n=b.n,a.m=b.m;
        F(i,1,a.n) F(j,1,a.m) a.a[i][j] = b.a[i][j];
    }
    inline friend Matrix operator + (Matrix a,Matrix b){
        Matrix c; c.init();
        c.n=a.n, c.m=a.m;
        F(i,1,c.n) F(j,1,c.m) c.a[i][j] = (a.a[i][j] + b.a[i][j]) % mod;
        return c;
    }
    inline friend Matrix operator - (Matrix a,Matrix b){
        Matrix c; c.init();
        c.n=a.n, c.m=a.m;
        F(i,1,c.n) F(j,1,c.m) c.a[i][j] = (a.a[i][j] - b.a[i][j]) % mod;
        return c;
    }
    inline friend Matrix operator * (Matrix a,Matrix b){
        Matrix c; c.init();
        c.n = a.n, c.m = b.m;
        F(i,1,c.n) F(j,1,c.m) F(k,1,a.m)
            c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
        return c;
    }
    inline friend bool operator == (Matrix a,Matrix b){
        if(a.n!=b.n || a.m!=b.m) return 0;
        F(i,1,a.n) F(j,1,a.m) if(a.a[i][j] != b.a[i][j]) return 0;
        return 1;
    }
    inline friend bool operator != (Matrix a,Matrix b){ return !(a==b); }
    inline friend void operator += (Matrix &a,Matrix b){ a=a+b; }
    inline friend void operator -= (Matrix &a,Matrix b){ a=a-b; }
};

线性筛(带了欧拉函数和莫比乌斯函数)

int prm[N], tot;
int phi[N], mu[N];
inline void ola(){
    F(i,2,N-50){
        if(!p[i]){
            prm[++tot] = i;
            phi[i] = i-1;
            mu[i] = -1;
        }
        for(int j=1; j<=tot && i*prm[j]<=N-50; j++){
            p[i] = true;
            if(i%prm[j]){
                phi[i*prm[j]] = phi[i] * phi[prm[j]];
                mu[i*prm[j]] = -mu[i];
            }else{
                phi[i*prm[j]] = phi[i] * prm[j];
                mu[i*prm[j]] = 0;
                break;
            }
        }
    }
}

快速幂

inline int fast_power(int x,int p){
  //求x的p次方
    int ans = 1;
    while(p){
        if(p % 2) ans = ans * x % mod;
        x = x * x % mod;
        p /= 2;
    }
    return ans;
}

建图——邻接表的连边

无边权

int tot,head[N],ver[N],nxt[N];

inline void add(int x,int y){
    ver[++tot] = y;
    nxt[tot] = head[x];
    head[x] = tot;
}

有边权

int tot,head[N],ver[N],nxt[N],d[N];

inline void add(int x,int y,int z){
    ver[++tot] = y;
    nxt[tot] = head[x];
    head[x] = tot;
    d[tot] = z;
}

图论

DSU 并查集

int dsu[N];

inline int find(int x){//查找根节点 
    return dsu[x] == x ? x : dsu[x] = find(dsu[x])
}

inline void merge(int x,int y){//合并两棵树 
    int xx = find(x), yy = find(y);
    dsu[xx] = yy;
}

inline bool union_find(int x,int y){//查找两个节点是否在同一棵树上,即根节点是否相同 
    return find(x) == find(y);
}

MST 最小生成树

Kruskal

int n,m;
int dsu[M];
struct edge{
    int u,v,val;
}a[N];
inline int find(int x){
    return (x == dsu[x]) ? x : dsu[x] = find(dsu[x]);
}
inline void merge(int x,int y){
    int xx = find(x),yy = find(y);
    dsu[xx] = yy;
}
inline bool cmp(edge a,edge b){
    return a.val < b.val;
}
signed main(){
    sort(a + 1,a + m + 1,cmp);
    int cnt = 0,ans = 0;
    F(1,i,m){
        if(find(a[i].u) != find(a[i].v)){
            cnt ++;
            ans += a[i].val;
            merge(a[i].u,a[i].v);
        }
        if(cnt == n - 1) break;
    }
    cout << ans;
    return 0;
}

数论

拓展欧几里得

inline int exgcd(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1,y = 0;
        return a;
    }
    int x2,y2;
    int d = exgcd(b,a % b,x2,y2);
    x = y2,y = x2 - a / b * y2;
  return d; 
}

字符串算法

Trie 字典树

int idx,tr[N][70],cnt[N];
char c[N];

inline int gt(char c){
    if(c>='A'&&c<='Z') return c-'A';
    if(c>='a'&&c<='z') return c-'a'+26;
    else return c-'0'+52;
}
inline void insert(char c[]){
    int len=strlen(c),p=0;
    F(i,0,len-1){
        int t=gt(c[i]);
        if(!tr[p][t]) tr[p][t]=++idx;
        p=tr[p][t];
        cnt[p]++;
    }
}
inline int find(char c[]){
    int len=strlen(c),p=0;
    F(i,0,len-1){
        int t=gt(c[i]);
        if(!tr[p][t]) return 0;
        p=tr[p][t];
    }
    return cnt[p];
}

最小表示法

inline string get_min_expression(string s){
    int k=0,i=0,j=1,n=s.size();
    while(i<n && j<n && k<n){
        if(s[(i+k)%n] == s[(j+k)%n]) k++;
        else{
            s[(i+k)%n]>s[(j+k)%n] ? i+=k+1 : j+=k+1;
            if(i==j) i++;
            k=0;
        }
    }
    i=min(i,j);
    return s.substr(i)+s.substr(0,i);
}

树形数据结构

Treap 无旋平衡树

struct Treap{
    #define ls (tr[rt].l)
    #define rs (tr[rt].r)
    struct treap{
        int l, r;//表示其左右儿子的结点编号
        int val, rnd;//BST的权值与heap的值
        int siz;//以其为根的子树的结点个数
    }tr[N];
    int root = 0, n = 0;
    //分别代表根和数的个数

    inline void newnode(int v){
        tr[++n].val = v;
        tr[n].rnd = rng();
        tr[n].siz = 1;
    }//新增一个结点

    inline void pushup(int rt){
        tr[rt].siz = tr[ls].siz + tr[rs].siz +1;
    }
    inline void split(int rt, int v, int &x, int &y){
        if(rt == 0){
            x = y = 0;
            return ;
        }

        if(tr[rt].val <= v){
            x = rt;
            split(rs, v, rs, y);
        }else{
            y = rt;
            split(ls, v, x, ls);
        }//极其重要!极其巧妙! 

        pushup(rt);
    }
    inline int merge(int x, int y){
        if(!x || !y) return x+y;
        if(tr[x].rnd < tr[y].rnd){
            tr[x].r = merge(tr[x].r, y);
            pushup(x);
            return x;
        }else{
            tr[y].l = merge(x, tr[y].l);
            pushup(y);
            return y;
        }
    }//基本操作:分裂与合并

    inline void insert(int v){
        int x, y;
        split(root, v, x, y);
        newnode(v);
        int z = n;
        root = merge(merge(x, z), y);
    }//插入结点
    inline void del(int v){
        int x, y, z;
        split(root, v, x, z);
        split(x, v-1, x, y);
        y = merge(tr[y].l, tr[y].r);//若y有子树,合并(保留)其子树 
        root = merge(merge(x, y), z);
    }//删除结点 
    inline int rank(int v){
        int x, y;
        split(root, v-1, x, y);
        int ans = tr[x].siz + 1;
        root = merge(x, y);
        return ans;
    }//查找排名 
    inline int topk(int rt, int k){
        int lsz = tr[ls].siz;
        if(k == lsz+1) return tr[rt].val;
        if(k <= lsz) return topk(ls, k);
        return topk(rs, k - lsz - 1);
    }//查询第k小的数 
    inline int get_pre(int v){
        int x, y;
        split(root, v-1, x, y);
        int ans = topk(x, tr[x].siz);
        root = merge(x, y);
        return ans;
    }//查找前驱 
    inline int get_suc(int v){
        int x, y;
        split(root, v, x, y);
        int ans = topk(y, 1);
        root = merge(x, y);
        return ans;
    }//查找后继 
}T;

Splay 平衡树

struct Splay{
    int rt=0,tot=0;
    struct tree{
        int s[2];   //s[0]表示左儿子,s[1]表示右儿子 
        int siz,val;
        int fa;
    }tr[N<<1];
    #define fa(x) tr[x].fa
    #define ls(x) tr[x].s[0]
    #define rs(x) tr[x].s[1]
    inline void pushup(int x){ tr[x].siz = tr[ls(x)].siz+tr[rs(x)].siz+1; }
    inline void clear(int x){ tr[x].siz=fa(x)=ls(x)=rs(x)=tr[x].val=0; }
    inline bool get(int x){
        return rs(fa(x))==x;
    }//返回 0 表示左儿子,返回 1 表示右儿子 

    inline void newnode(int val){
        clear(++tot);
        tr[tot].val = val;
        tr[tot].siz=1;
    }
    inline void ronate(int x){
        int c = get(x), y = fa(x), z = fa(y);
        if(tr[x].s[!c]) fa(tr[x].s[!c]) = y;    //若有与自身左右不一样的儿子,则"过继"至原父亲
        tr[y].s[c] = tr[x].s[!c];
        tr[x].s[!c] = y; fa(y) = x;     //原父亲成为儿子
        fa(x) = z;          //原儿子成为原先父亲的父亲的儿子 
        if(z) tr[z].s[(y==rs(z))] = x;
        pushup(y), pushup(x);
    }
    inline void splay(int x){
        while(fa(x)){
            int y = fa(x);
            if(fa(y)) ronate(get(x)==get(y) ? y : x);   //若自身与父亲同向,则先旋转父亲以维护平衡性
            ronate(x);
        }
        rt=x;
    }//将某个非根节点旋转至根上 

    inline void insert(int val){
        int now=rt, f=0;
        while(now){
            f = now;
            now = tr[now].s[val > tr[now].val];
        }//在二叉搜索树上寻找当前权值的节点应在的位置 
        newnode(val);       //创建新节点 
        fa(tot) = f;
        tr[f].s[val > tr[f].val] = tot;     //将新创建的节点与其父亲连边 
        splay(tot);     //将新节点旋转至根 
    }//插入新节点 
    inline void del(int val){
        int now=rt,f=0;
        while(now && tr[now].val != val){
            f=now;
            now = tr[now].s[val>tr[now].val];
        }//根据权值,在二叉搜索树上寻找应删除节点的位置 
        if(!now){
            splay(f);
            return ;
        }//若没有则旋转其父亲,并直接返回 
        splay(now);
        int cur = ls(now);
        if(!cur){       //若要删除的点没有左儿子 
            rt = rs(now);   //右儿子为根 
            if(rt) fa(rt) = 0;
            clear(now); //删除 
            return ;
        }
        while(rs(cur)) cur = rs(cur);   //找到左子树中最右边的叶子 
        rs(cur) = rs(now);
        if(rs(now)) fa(rs(now)) = cur;  //右子树的根成为该叶子的儿子以维护二叉搜索树的性质 
        fa(ls(now)) = 0;
        clear(now);         //删除节点 
        pushup(cur);
        splay(cur);
    }//删除一个节点 
    inline int rhk(int val){
        int res=1,now=rt,f=0;
        while(now){
            f = now;
            if(tr[now].val<val){
                res += tr[ls(now)].siz+1;   //左子树上的点和当前点都比其小
                now = rs(now);
            }else now = ls(now);
        }
        splay(f);
        return res;
    }//查询某个数的 rank 值
    inline int kth(int cnt){
        int now=rt;
        while(now){
            int t = tr[ls(now)].siz+1;
            if(t < cnt) cnt -= t, now=rs(now);
            else if(t==cnt) break;
            else now=ls(now);
        }
        splay(now);
        return tr[now].val;
    }//查询第 k 小的值 
    inline int pre(int val){
        int res=0,now=rt,f=0;
        while(now){
            f=now;
            if(tr[now].val>=val) now=ls(now);
            else res=tr[now].val,now=rs(now);
        }
        splay(f);
        return res;
    }//查询前驱 
    inline int nxt(int val){
        int res=0,now=rt,f=0;
        while(now){
            f=now;
            if(tr[now].val<=val) now=rs(now);
            else res=tr[now].val,now=ls(now);
        }
        splay(f);
        return res;
    }//查询后继 
}T;