Splay树模板

#include<bits/stdc++.h>
#define root_right ch[root][1]
using namespace std;
const int MX = 4e5 + 5;

int a[MX], S[MX], n;
int root, rear;         //根节点,节点总数
int rem[MX], tot;       //经过删除后未被使用的节点
int ch[MX][2], fa[MX];
int val[MX], sum[MX][2];
int sta[MX];
int sz[MX];

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

void NewNode(int &rt, int father, int v, int s) {
    if (tot) rt = rem[tot--];
    else rt = ++rear;
    fa[rt] = father;
    ch[rt][0] = ch[rt][1] = 0;
    val[rt] = v;
    sta[rt] = s;
    sum[rt][s] = v;
    sum[rt][s ^ 1] = 0;
    sz[rt] = 1;
}
void PushUP(int rt) {
    int ls = ch[rt][0], rs = ch[rt][1];
    sz[rt] = sz[ls] + sz[rs] + 1;
    sum[rt][0] = gcd(sum[ls][0], sum[rs][0]);
    sum[rt][1] = gcd(sum[ls][1], sum[rs][1]);
    if (sta[rt] == 0) sum[rt][0] = gcd(sum[rt][0], val[rt]);
    else sum[rt][1] = gcd(sum[rt][1], val[rt]);
}
void build(int &rt, int l, int r, int father) {
    if (l > r) return;
    int m = (l + r) >> 1;
    NewNode(rt, father, a[m], S[m]);
    build(ch[rt][0], l, m - 1, rt);
    build(ch[rt][1], m + 1, r, rt);
    PushUP(rt);
}
void init() {
    root = rear = tot = 0;
    NewNode(root, 0, 0, 0);  //一共n+2个节点
    NewNode(ch[root][1], root, 0, 0);
    for (int i = 1; i <= n; i++) scanf("%d%d", &a[i], &S[i]);
    build(ch[ch[root][1]][0], 1, n, ch[root][1]);
    PushUP(root);
}
void Rotate(int rt, int op) { //op=0表示左旋,op=1表示右旋
    int father = fa[rt];
    //PushDown(father); PushDown(rt);
    ch[father][!op] = ch[rt][op];
    fa[ch[rt][op]] = father;
    if (fa[father])
        ch[fa[father]][ch[fa[father]][1] == father] = rt;
    fa[rt] = fa[father];
    ch[rt][op] = father;
    fa[father] = rt;
    PushUP(father);  //father变成子节点,只要更新father
}
void Splay(int rt, int f) {
    //PushDown(rt);
    while (fa[rt] != f) {
        int father = fa[rt];
        if (fa[father] == f) Rotate(rt, ch[father][0] == rt);
        else {
            int gf = fa[father];
            if (ch[gf][0] == father) {
                if (ch[father][0] == rt) Rotate(father, 1), Rotate(rt, 1);
                else Rotate(rt, 0), Rotate(rt, 1);
            } else {
                if (ch[father][1] == rt) Rotate(father, 0), Rotate(rt, 0);
                else Rotate(rt, 1), Rotate(rt, 0);
            }
        }
    }
    PushUP(rt);   //更新rt
    if (f == 0) root = rt;
}
int get_kth(int rt, int k) {
    int t = sz[ch[rt][0]] + 1, ret;
    if (t == k) ret = rt;
    else if (t > k) ret = get_kth(ch[rt][0], k);
    else ret = get_kth(ch[rt][1], k - t);
    return ret;
}
int Query(int L, int R, int s) {
    Splay(get_kth(root, L), 0);      //将第L-1个数旋转到根节点
    Splay(get_kth(root, R + 2), root); //将第R+1个数旋转到根节点的右儿子
    int ans = sum[ch[ch[root][1]][0]][s];
    return ans == 0 ? -1 : ans;
}
void Insert(int p, int v, int s) {
    Splay(get_kth(root, p + 1), 0); //将第p个数旋转到根节点
    Splay(get_kth(root, p + 2), root); //将第p+1个数旋转到根节点的右儿子,此时该节点没有左儿子
    NewNode(ch[ch[root][1]][0], ch[root][1], v, s);
    PushUP(ch[root][1]);
    PushUP(root);
}
void erase(int rt) {
    if (!rt)return;
    fa[rt] = 0;
    rem[++tot] = rt;
    erase(ch[rt][0]);
    erase(ch[rt][1]);
}
void Delete(int p) {
    Splay(get_kth(root, p), 0);       //将第p-1个数旋转到根节点
    Splay(get_kth(root, p + 2), root);//将第p+1个数旋转到根节点的右儿子,此时该节点左儿子为p
    erase(ch[ch[root][1]][0]);
    ch[ch[root][1]][0] = 0;
    PushUP(ch[root][1]);
    PushUP(root);
}
void Change1(int p) {
    Splay(get_kth(root, p + 1), 0);   //将第p个数旋转到根节点
    sta[root] ^= 1;
    PushUP(root);
}
void Change2(int p, int v) {
    Splay(get_kth(root, p + 1), 0);   //将第p个数旋转到根节点
    val[root] = v;
    PushUP(root);
}
int main() {
    //freopen("in.txt", "r", stdin);
    int m, l, r, v, s, p; char op[2];
    while (~scanf("%d%d", &n, &m)) {
        init();
        while (m--) {
            scanf("%s", op);
            if (op[0] == 'Q') {
                scanf("%d%d%d", &l, &r, &s);
                printf("%d\n", Query(l, r, s));
            }
            if (op[0] == 'I') {
                scanf("%d%d%d", &p, &v, &s);
                Insert(p, v, s);
            }
            if (op[0] == 'D') {
                scanf("%d", &p);
                Delete(p);
            }
            if (op[0] == 'R') {
                scanf("%d", &p);
                Change1(p);
            }
            if (op[0] == 'M') {
                scanf("%d%d", &p, &v);
                Change2(p, v);
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值