Lights--ZOJ月赛--伸展树

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
题意:
五种操作:
Q L R S 询问区间状态为S的最大公约数。
I I K S 插入点。
D I     删除点。
R I     改变灯的状态。
M I X   修改灯的值。
思路:伸展树要维护区间的大小,状态为0的灯数目,状态为1的灯数目,总灯数目,点权,状态为1的最大公约数和状态为2的最大公约数。
     关键在于PUSHUP函数的维护。数目的维护很容易。
     公约数的维护要分类讨论,根据状态0,1的灯是否存在。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
using namespace std;
#define maxn 400080
#define Key_value ch[ch[root][1]][0]
int Lkey[maxn],Lstate[maxn];
int n,m;
inline int gcd(int a,int b)
{
	if(b == 0)	return a;
	return gcd(b,a%b);
}


struct SplayTree
{
	int pre[maxn],key[maxn],ch[maxn][2],size[maxn],gcd0[maxn],gcd1[maxn],sta[maxn];
	int size0[maxn],size1[maxn];
	int root,cnt;

	void Treaval(int x)
	{
		if(!x)	return;
		Treaval(ch[x][0]);
		printf("结点: %d  左儿子:  %d   右儿子:  %d  Key:  %d   Size:  %d  Size0:  %d  Size1:  %d   sta:  %d   gcd0:  %d   gcd1:  %d\n",x,ch[x][0],ch[x][1],key[x],size[x],size0[x],size1[x],sta[x],gcd0[x],gcd1[x]);
		Treaval(ch[x][1]);
	}
	void debug()
	{
		printf("根节点是:%d",root);
		Treaval(root);
	}

	
	void init()
	{
		cnt = root = 0;
		ch[0][0] = ch[0][1] = pre[0] = size[0] = size0[0] = size1[0] = sta[0] = gcd1[0] = gcd0[0] = key[0] = 0;
		NewNode(root,0,0,0);
		NewNode(ch[root][1],0,0,root);
		PushUp(root);
		BuildTree(Key_value,1,n,ch[root][1]);
		PushUp(ch[root][1]);
		PushUp(root);
	}
	
	void NewNode(int & r,int k,int s,int father)///没错
	{
		r = ++cnt;
		ch[r][0] = ch[r][1] = 0;
		pre[r] = father;
		key[r] = k;
		sta[r] = s;
		size[r] = 1;
		size0[r] = (s == 0);
		size1[r] = (s == 1);
		gcd1[r] = k;
		gcd0[r] = k;
	}

	//维护区间大小,状态为0的数目,状态为1的数目,2个最大公约数
	void PushUp(int x)
	{
		int l = ch[x][0],r = ch[x][1];
		size[x] = size[l] + size[r] + 1;
		size0[x] = size0[l] + size0[r] + (sta[x] == 0);
		size1[x] = size1[l] + size1[r] + (sta[x] == 1);
		if(sta[x] == 1)
		{
			//维护GCD0
			if(size0[l] > 0 && size0[r] == 0)
			{
				gcd0[x] = gcd0[l];
			}
			else if(size0[l] == 0 && size0[r] > 0)
			{
				gcd0[x] = gcd0[r];
			}
			else if(size0[l] == 0 && size0[r] == 0)
			{
				gcd0[x] = -1;
			}
			else
			{
				gcd0[x] = gcd(gcd0[l],gcd0[r]);
			}
			//维护GCD1
			if(size1[l] > 0 && size1[r] == 0)
			{
				gcd1[x] = gcd(gcd1[l],key[x]);
			}
			else if(size1[l] == 0 && size1[r] > 0)
			{
				gcd1[x] = gcd(gcd1[r],key[x]);
			}
			else if(size1[l] == 0 && size1[r] == 0)
			{
				gcd1[x] = key[x];
			}
			else 
			{
				gcd1[x] = gcd(gcd1[l],key[x]);
				gcd1[x] = gcd(gcd1[r],gcd1[x]);
			}
		}
		else 
		{
			//维护GCD0
			if(size0[l] > 0 && size0[r] == 0)
			{
				gcd0[x] = gcd(gcd0[l],key[x]);
			}
			else if(size0[l] == 0 && size0[r] > 0)
			{
				gcd0[x] = gcd(gcd0[r],key[x]);
			}
			else if(size0[l] == 0 && size0[r] == 0)
			{
				gcd0[x] = key[x];
			}
			else 
			{
				gcd0[x] = gcd(key[x],gcd0[l]);
				gcd0[x] = gcd(gcd0[x],gcd0[r]);
			}
			//维护GCD1
			if(size1[l] > 0 && size1[r] == 0)
			{
				gcd1[x] = gcd1[l];
			}
			else if(size1[l] == 0 && size1[r] > 0)
			{
				gcd1[x] = gcd1[r];
			}
			else if(size1[l] == 0 && size1[r] == 0)
			{
				gcd1[x] = -1;
			}
			else 
			{
				gcd1[x] = gcd(gcd1[l],gcd1[r]);
			}
		}
	}


	void BuildTree(int & r,int L,int R,int father)
	{
		if(L > R)	return;
		int mid = (L+R) >> 1;
		NewNode(r,Lkey[mid],Lstate[mid],father);
		BuildTree(ch[r][0],L,mid-1,r);
		BuildTree(ch[r][1],mid+1,R,r);
		PushUp(r);
	}

	void Rotate(int x,int kind)
	{
		int y = pre[x];
		ch[y][!kind] = ch[x][kind];
		pre[ch[x][kind]] = y;
		if(pre[y])
			ch[pre[y]][ch[pre[y]][1] == y] = x;
		pre[x] = pre[y];
		ch[x][kind] = y;
		pre[y] = x;
		PushUp(y);
	}

	void Splay(int r,int goal)
	{
		while(pre[r] != goal)
		{
			if(pre[pre[r]] == goal)
				Rotate(r,ch[pre[r]][0] == r);
			else 
			{
				int y = pre[r];
				int kind = (ch[pre[y]][0]==y);
				if(ch[y][kind] == r)
				{
					Rotate(r,!kind);
					Rotate(r,kind);
				}
				else 
				{
					Rotate(y,kind);
					Rotate(r,kind);
				}
			}
		}
		PushUp(r);
		if(goal == 0) root = r;
	}

	int Get_Kth(int r,int k)
	{
		int t = size[ch[r][0]] + 1;
		if(t == k)
			return r;
		if(t > k)
			return Get_Kth(ch[r][0],k);
		else return Get_Kth(ch[r][1],k-t);
	}

	int Get_Min(int r)
	{
		while(ch[r][0])
		{
			r = ch[r][0];
		}
		return r;
	}

	int Get_Max(int r)
	{
		while(ch[r][1])
			r = ch[r][1];
		return r;
	}

	void Insert(int pos,int k,int s)//插入灯操作,没错
	{
		int x = Get_Kth(root,pos+1);
		Splay(x,0);
		int y = Get_Min(ch[root][1]);
		Splay(y,root);
		NewNode(Key_value,k,s,ch[root][1]);
		PushUp(ch[root][1]);
		PushUp(root);
	}

	void Delete(int l)//删除操作
	{
		int x = Get_Kth(root,l);
		Splay(x,0);
		int y = Get_Kth(root,l+2);
		Splay(y,root);
		pre[Key_value] = 0;
		Key_value = 0;
		PushUp(ch[root][1]);
		PushUp(root);
	}

	int Query(int l,int r,int s)//询问操作
	{
		int x = Get_Kth(root,l);
		Splay(x,0);
		int y = Get_Kth(root,r+2);
		Splay(y,root);
		if((s == 1 && size1[Key_value] == 0) || (s == 0 && size0[Key_value] == 0))	return -1;
		return s?gcd1[Key_value]:gcd0[Key_value];
	}

	void Flip(int l)//改变状态操作
	{
		int x = Get_Kth(root,l);
		Splay(x,0);
		int y = Get_Kth(root,l+2);
		Splay(y,root);
		sta[Key_value] ^= 1;
		size0[Key_value] ^= 1;
		size1[Key_value] ^= 1;

		if(sta[Key_value] == 0)
		{
			gcd0[Key_value] = key[Key_value];
		}
		else 
		{
			gcd1[Key_value] = key[Key_value];
		}
		PushUp(ch[root][1]);
		PushUp(root);
	}

	void Modify(int l,int k)//修改权操作
	{
		int x = Get_Kth(root,l);
		Splay(x,0);
		int y = Get_Kth(root,l+2);
		Splay(y,root);
		key[Key_value] = k;
		if(sta[Key_value] == 1)
		{
			gcd1[Key_value] = k;
		}
		else 
		{
			gcd0[Key_value] = k;
		}
		PushUp(ch[root][1]);
		PushUp(root);
	}

	void solve()
	{
		init();
		char ope[4];
		while(m--)
		{
			scanf("%s",ope);
			if(ope[0] == 'Q')
			{
				int l,r,s;
				scanf("%d%d%d",&l,&r,&s);
				printf("%d\n",Query(l,r,s));
			}
			else if(ope[0] == 'I')
			{
				int pos,key,s;
				scanf("%d%d%d",&pos,&key,&s);
				Insert(pos,key,s);
			}
			else if(ope[0] == 'D')
			{
				int pos;
				scanf("%d",&pos);
				Delete(pos);
			}
			else if(ope[0] == 'R')
			{
				int pos;
				scanf("%d",&pos);
				Flip(pos);
			}
			else
			{
				int pos,key;
				scanf("%d%d",&pos,&key);
				Modify(pos,key);
			}
		}
	}
}spt;

int main()
{
	//freopen("in.txt","r",stdin);
	while(scanf("%d%d",&n,&m)==2)
	{
		for(int i = 1;i <= n;i++)
			scanf("%d%d",&Lkey[i],&Lstate[i]);
		spt.solve();
	}
	return 0;
}

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值