ZOJ-3765 Lights(Splay树)

吴松
2023-12-01

Lights

Time Limit: 8 Seconds      Memory Limit: 131072 KB

Now you have N lights in a line. Don't worry - the lights don't have color. The only status they have is on and off. And, each light has a value, too.

There is a boring student in ZJU. He decides to do some boring operations to the lights:

  1. Q L R status - Query the GCD (Greatest Common Divisor) of the value of the given status lights in range [L, R]. For example, if now we have 3 lights which are {on, off and on}, and their value are {3, 5, 9}, then the GCD of the number of the lights on in [1, 3] is 3, and the lights off is 5.
  2. I i value status - Add a light just behind to ith light. The initial status and the value is given also.
  3. D i - Remove the ith light.
  4. R i - If ith light is on, turn it off, else turn it on.
  5. M i x - Modify the value of ith light to x.

Please help this boring guy to do this boring thing so that he can have time to find a girlfriend!

Input

The input contains multiple test cases. Notice there's no empty line between each test case.

For each test case, the first line of the a case contains two integers, N (1 ≤ N ≤ 200000) and Q (1 ≤ Q ≤ 100000), indicating the number of the lights at first and the number of the operations. In following N lines, each line contains two integers, Numi (1 ≤ Numi ≤ 1000000000) and Statusi (0 ≤ Statusi ≤ 1), indicating the number of the light i and the status of it. In following Q lines, each line indicating an operation, and the format is described above.

It is guaranteed that the range of the operations will be appropriate. For example, if there is only 10 lights, you will not receive an operation like "Q 1 11 0" or "D 11".

Output

For each Query operation, output an integer, which is the answer to the query. If no lights are with such status, please output -1.

Sample Input

3 12
27 1
32 0
9 1
Q 1 3 1
I 3 64 0
Q 2 4 0
Q 2 4 1
I 2 43 1
D 5
Q 1 2 1
M 1 35
Q 1 2 1
R 1
R 3
Q 1 2 1

Sample Output

9
32
9
27
35
-1

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;
}


 类似资料: