ZOJ 3765 Lights (伸展树)

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

Author: WANG, Xiajun
Source: ZOJ Monthly, March 2014

题意:有n个灯,5种操作,Q操作为查询区间[L,R]状态为state所有灯的GCD,I操作为在第i为后插入一个值为val,状态为state的灯,D操作为删除第i个灯,R操作为把第i个灯的状态取反,M操作为修改第i个灯的值

思路:伸展树的模板题,都是一些伸展树的常规操作,为了避免对边界的处理,在建树的时候多建两个虚节点,查询的时候把第L个节点伸展到根节点,把第R+2个节点伸展到根节点的右子节点,这样根节点右儿子的左儿子就是所查询的区间,在第i个位置插入的时候,把第L+1个节点伸展到根节点,第L+2个节点伸展到根节点的右子节点,然后把新的节点插入到根节点右儿子的左儿子,D R M操作都是把第L个节点伸展到根节点,把L+2个节点伸展到根节点的右子节点,然后对根节点右儿子的左儿子进行相关操作即可

#include <bits/stdc++.h>

#define ket root -> ch[1] -> ch[0]
using namespace std;

const int MAXN = 300010;
struct Node* null;
inline int GCD(int a,int b)
{
    if(b == 0) return a;
    return GCD(b,a % b);
}
struct Node
{
    Node *ch[2],*fa;
    int sum[2],val,state;
    int sz;
    //初始化一个节点
    Node()
    {
        ch[0] = ch[1] = fa = null;
        sum[0] = sum[1] = val = state = 0;
    }
    //将子节点的信息反馈给父节点
    inline void push_up()
    {
        if(this == null) return;
        sz = ch[0] -> sz + ch[1] -> sz + 1;
        sum[state] = GCD(val,GCD(ch[0] -> sum[state],ch[1] -> sum[state]));
        sum[!state] = GCD(ch[0] -> sum[!state],ch[1] -> sum[!state]);
    }
    //把节点P设为该节点的儿子
    inline void setc(Node* p,int d)
    {
        ch[d] = p;
        p -> fa = this;
    }
    //判断该节点是左儿子还是右儿子
    inline bool d()
    {
        return fa -> ch[1] == this;
    }
    //删除节点
    void Clear()
    {
        sz = 1;
        ch[0] = ch[1] = fa = null;
        val = sum[0] = sum[1] = state = 0;
    }
    //将父节点的信息传递给子节点
    inline void push_down()
    {

    }
    //判断是否是根节点
    inline bool isroot()
    {
        return fa == null || this != fa -> ch[0] && this != fa -> ch[1];
    }
};
inline void Rotate(Node* x)
{
    Node *f = x -> fa,*ff = x -> fa -> fa;
    f -> push_down();
    x -> push_down();
    int c = x -> d(),cc = f -> d();
    f -> setc(x -> ch[!c],c);
    x -> setc(f,!c);
    if(ff -> ch[cc] == f) ff -> setc(x,cc);
    else x -> fa = ff;
    f -> push_up();
}
inline void splay(Node* &root,Node* x,Node* goal)
{
    while(x -> fa != goal) {
        if(x -> fa -> fa == goal) Rotate(x);
        else {
            x -> fa -> fa -> push_down();
            x -> fa -> push_down();
            x -> push_down();
            bool f = x -> fa ->d();
            x -> d() == f ? Rotate(x -> fa) : Rotate(x);
            Rotate(x);
        }
    }
    x -> push_up();
    if(goal == null) root = x;
}
Node* get_kth(Node* r,int k)
{
    Node* x = r;
    x -> push_down();
    while(x -> ch[0] -> sz + 1 != k) {
        if(k < x -> ch[0] -> sz + 1) x = x -> ch[0];
        else {
            k -= x -> ch[0] -> sz + 1;
            x = x -> ch[1];
        }
        x -> push_down();
    }
    return x;
}
Node pool[MAXN],*tail;
Node *root;
int val[MAXN],state[MAXN];
Node* newnode(int val,int state,Node* fa)
{
    Node *x = tail++;
    x -> Clear();
    x -> state = state;
    x -> val = x -> sum[state] = val;
    x -> sum[!state] = 0;
    x -> fa = fa;
    return x;
}
void build(Node* &x,int l,int r,Node* fa)
{
    if(l > r) return;
    int mid = (l + r) / 2;
    x = newnode(val[mid],state[mid],fa);
    build(x -> ch[0],l,mid - 1,x);
    build(x -> ch[1],mid + 1,r,x);
    x -> push_up();
}
void init(int n)
{
    tail = pool;
    null = tail++;
    null -> fa = null -> ch[0] = null -> ch[1] = null;
    null -> state = null -> val = 0;
    null -> sz = 0;
    null -> sum[0] = null -> sum[1] = 0;
    //两个虚节点
    Node *p = tail++;
    p -> Clear();
    root = p;
    p = tail++;
    p -> Clear();
    root -> setc(p,1);
    build(ket,1,n,root -> ch[1]);
    root -> ch[1] -> push_up();
    root -> push_up();
}
/*void print(Node* root)
{
    if(root == null) return;
    else {
        print(root -> ch[0]);
        printf("jiedian %d lson %d rson %d \n",root -> val,root -> ch[0] -> val ,root -> ch[1] -> val);
        print(root -> ch[1]);
    }
}*/
int Query(int L,int R,int state)
{
    splay(root,get_kth(root,L),null);
    splay(root,get_kth(root,R + 2),root);
    return ket -> sum[state];
}
void Insert(int L,int val,int state)
{
    splay(root,get_kth(root,L + 1),null);
    splay(root,get_kth(root,L + 2),root);
    ket = newnode(val,state,root -> ch[1]);
    root -> ch[1] -> push_up();
    root -> push_up();
}
void Delete(int L)
{
    splay(root,get_kth(root,L),null);
    splay(root,get_kth(root,L + 2),root);
    ket = null;
    root -> ch[1] -> push_up();
    root -> push_up();
}
void Reverse(int L)
{
    splay(root,get_kth(root,L),null);
    splay(root,get_kth(root,L + 2),root);
    ket -> state ^= 1;
    swap(ket -> sum[0],ket -> sum[1]);
    root -> ch[1] -> push_up();
    root -> push_up();
}
void Modify(int L,int val)
{
    splay(root,get_kth(root,L),null);
    splay(root,get_kth(root,L + 2),root);
    ket -> val = val;
    ket -> sum[ket -> state] = val;
    root -> ch[1] -> push_up();
    root -> push_up();
}
int main(void)
{
    int n,q;
    while(scanf("%d %d",&n,&q) != EOF) {
        for(int i = 1; i <= n; i++) {
            scanf("%d%d",&val[i],&state[i]);
        }
        init(n);
        char op[2];
        int L,R,_val,_state;
        while(q--) {
            scanf("%s",op);
            if(op[0] == 'Q') {
                scanf("%d%d%d",&L,&R,&_state);
                int ans = Query(L,R,_state);
                if(ans == 0) printf("-1\n");
                else printf("%d\n",ans);
            }
            else if(op[0] == 'I') {
                scanf("%d %d %d",&L,&_val,&_state);
                Insert(L,_val,_state);
            }
            else if(op[0] == 'D') {
                scanf("%d",&L);
                Delete(L);
            }
            else if(op[0] == 'R') {
                scanf("%d",&L);
                Reverse(L);
            }
            else {
                scanf("%d %d",&L,&_val);
                Modify(L,_val);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/81392839
今日推荐