ZOJ3765 Lights splay

维护区间的GCD,增加数字。那么毫无疑问是维护区间的神器SPLAY了(因为这里涉及了动态的修改数字序列,在其中增加内容),至于灯开还是关。。。不用想太多,直接维护两个gcd即可。这道题目基本算是裸的splay了数组开大了,,居然一直TLE,想不通。。。

其实基本的splay题目,只要理解了旋转操作,以及获取区间的操作,基本上splay的基本操作就等于掌握了。

至于down和up的用处

我认为

down 是用来成段的维护数列中的数据,用来处理延迟标记,这里与线段树大同小异,有的题目中可能down根本没有用,因为不用维护延迟标记

up 对于splay来说我认为必不可少,因为你要维护一个size域,用来表示一个子树的节点数,这个数据域在后来选区第i个节点时一定会用到。并且,当我们要维护一个区间中的最大值或最小值神马的 , 之前的一道维修数列好像以维护一个序列长度,这道题则是GCD,那么我们就要用到up

总之down用来延迟更新数字序列的数据而up则用来向上更新我们要求解的内容对于不同的题目down可能没有,而up基本都有。


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. L R status - Query the GCD (Greatest Common Divisor) of the value of the given status lights in range [LR]. 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 value status - Add a light just behind to ith light. The initial status and the value is given also.
  3. i - Remove the ith light.
  4. i - If ith light is on, turn it off, else turn it on.
  5. 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


#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>

using namespace std;

#define MAXN 300010
#define INF 0x3ffffff

int ss[MAXN],a[MAXN],n;
int next[MAXN];

long long gcd1(long long a,long long b)
{
    return a%b==0?b:gcd1(b,a%b);
}
long long gcd(long long a,long long b)
{
    if(a==-1 && b!=-1) return b;
    if(a==-1 && b==-1) return -1;
    if(a!=-1 && b==-1) return a;
    return gcd1(a,b);
}

struct nodes
{
    int ch[2],f;
    int on,size,w;
    long long key,gcdon,gcdoff;
}node[MAXN];

void init()
{
    for(int i=0;i<MAXN-10;i++)
        next[i]=i+1;
}

int newnode(long long key,int on)
{
    int p=next[0];
    next[0]=next[p];
    node[p].key=key;
    node[p].w=node[p].size=1;
    node[p].on=on;
    if(on)
        node[p].gcdon=key,node[p].gcdoff=-1;
    else
        node[p].gcdoff=key,node[p].gcdon=-1;
    node[p].ch[0]=node[p].ch[1]=node[p].f=0;
    return p;
}

void delnode(int p)
{
    next[p]=next[0];
    next[0]=p;
}

struct spt
{
    int root;
    void clear()
    {
        root=0;
    }
    void rotate(int x,int c)
    {
        int y=node[x].f;
        node[y].ch[!c]=node[x].ch[c];
        if(node[x].ch[c])
                node[node[x].ch[c]].f=y;
        node[x].f=node[y].f;
        if(node[y].f)
        {
            if(node[node[y].f].ch[0]==y)
                node[node[y].f].ch[0]=x;
            else
                node[node[y].f].ch[1]=x;
        }
        node[x].ch[c]=y;
        node[y].f=x;
        push_up(y);
        if(y==root) root=x;
    }
    void splay(int x,int f)
    {
        for(;node[x].f!=f;)
        {
            if(node[node[x].f].f==f)
            {
                if(node[node[x].f].ch[0]==x)
                    rotate(x,1);
                else
                    rotate(x,0);
            }
            else
            {
                int y=node[x].f;
                int z=node[y].f;
                if(node[z].ch[0]==y)
                {
                    if(node[y].ch[0]==x)
                        rotate(y,1),rotate(x,1);
                    else
                        rotate(x,0),rotate(x,1);
                }
                else
                {
                    if(node[y].ch[1]==x)
                        rotate(y,0),rotate(x,0);
                    else
                        rotate(x,1),rotate(x,0);
                }
            }
        }
        push_up(x);
        if(!f) root=x;
    }
    void remove()
    {
        int t=root;
        if(node[t].ch[1])
        {
            root=node[root].ch[1];
            select(1,0);
            node[root].ch[0]=node[t].ch[0];
            if(node[t].ch[0]) node[node[t].ch[0]].f=root;
        }
        else root=node[root].ch[0];
        node[root].f=0;
        push_up(root);
        delnode(t);
    }
    void CHANGELIGHT(int x){
        select(x+1,0);
        node[root].on=node[root].on^1;
        push_up(root);
    }
    void insert(int x,long long a,int s)
    {
        int p=newnode(a,s);
        select(x+1,0);
        x=getmin(node[root].ch[1]);
        splay(x,root);
        node[node[root].ch[1]].ch[0]=p;
        node[p].f=x;
        push_up(p);
        push_up(node[root].ch[1]);
        push_up(root);
    }
    long long GCDA2BON(int a,int b)
    {
        select(a,0);
        select(b+2,root);
        push_up(node[root].ch[1]);
        push_up(root);
        return node[node[node[root].ch[1]].ch[0]].gcdon;
    }
    long long GCDA2BOFF(int a,int b)
    {
        select(a,0);
        select(b+2,root);
        push_up(node[root].ch[1]);
        push_up(root);
        return node[node[node[root].ch[1]].ch[0]].gcdoff;
    }
    int select(int k,int rt)
    {
        int tmp,t=root;
        for(;;)
        {

            int l=node[node[t].ch[0]].size;
            if(k>l && k<=l+node[t].w) break;
            if(k<=l)
                t=node[t].ch[0];
            else
                k-=(l+node[t].w),t=node[t].ch[1];
        }
        splay(t,rt);
        return t;
    }
     int getmin(int p)
    {
        while(node[p].ch[0])
            p=node[p].ch[0];
        return p;
    }
    void push_up(int rt)
    {
        if(!rt) return;
        int l=node[rt].ch[0];
        int r=node[rt].ch[1];
        int ret,re2,anl=node[rt].w;
        if(l) anl+=node[l].size;
        if(r) anl+=node[r].size;
        node[rt].size=anl;
        if(node[rt].on){
            ret=node[rt].key;
            re2=-1;
            if(l) ret=gcd(ret,node[l].gcdon),re2=gcd(re2,node[l].gcdoff);
            if(r) ret=gcd(ret,node[r].gcdon),re2=gcd(re2,node[r].gcdoff);
        }
        else
        {
            ret=-1;
            re2=node[rt].key;
            if(l) ret=gcd(ret,node[l].gcdon),re2=gcd(re2,node[l].gcdoff);
            if(r) ret=gcd(ret,node[r].gcdon),re2=gcd(re2,node[r].gcdoff);
        }
        node[rt].gcdon=ret;
        node[rt].gcdoff=re2;
    }
    void modify(int x,long long y){
        select(x+1,0);
        node[root].key=y;
        push_up(root);
    }
    void del(int p)
    {
        if(!p) return;
        del(node[p].ch[0]);
        del(node[p].ch[1]);
        delnode(p);
    }
    int build(int l,int r,int f)
    {
        if(l>r) return 0;
        int m=(l+r)>>1;
        int p=newnode(a[m],ss[m]);
        node[p].f=f;
        node[p].ch[0]=build(l,m-1,p);
        node[p].ch[1]=build(m+1,r,p);
        push_up(p);
        return p;
    }
};

spt s1;

void prepare()
{
    s1.clear();
    s1.root=newnode(-1,0);
    node[s1.root].ch[1]=newnode(-1,0);
    node[node[s1.root].ch[1]].f=s1.root;
    node[node[s1.root].ch[1]].ch[0]=s1.build(1,n,node[s1.root].ch[1]);
    s1.push_up(node[s1.root].ch[1]);
    s1.push_up(s1.root);
}

void print(int rt){
    if(!rt) return;
    cout<<rt<<" "<<node[rt].key<<" "<<node[rt].size<<endl;
    print(node[rt].ch[0]);
    print(node[rt].ch[1]);
}

int main()
{
    char q[10];
    int x,y,z;
    init();
    int m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i],&ss[i]);
        prepare();
        for(int i=0;i<m;i++)
        {
            scanf("%s",q);

            if(strcmp(q,"Q")==0)
            {
                scanf("%d%d%d",&x,&y,&z);

                if(z==1) printf("%lld\n",s1.GCDA2BON(x,y));
                else printf("%lld\n",s1.GCDA2BOFF(x,y));
            }
            if(strcmp(q,"I")==0)
            {
                scanf("%d%d%d",&x,&y,&z);
                s1.insert(x,y,z);
            }
            if(strcmp(q,"D")==0)
            {
                scanf("%d",&x);
                s1.select(x+1,0);
                s1.remove();
            }
            if(strcmp(q,"R")==0)
            {
                scanf("%d",&x);
                s1.CHANGELIGHT(x);
            }
            if(strcmp(q,"M")==0)
            {
                scanf("%d%d",&x,&y);
                s1.modify(x,y);
            }
        }
        s1.del(s1.root);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值