做题记录整理数据结构/线段树3 P3822 [NOI2017] 整数(2022/10/17)

P3822 [NOI2017] 整数

为什么这玩意是双tag呢

因为他按理来说正解是用线段树来做的,但是有很多题解都是直接上set搞的,所以就两个tag都打上了

首先我们可以想到用bitset来表示这个整数,然后我们就会发现所谓的修改直接暴力改就完事

然后正负分开记录,询问的时候在加起来

若当前位相同,后缀非负则答案为 0,否则为 1。

若当前位不同,后缀非负则答案为 1,否则为 0。

我们会发现它大部分时候其实都是相同的,我们可以用set记录正负数组不同的位置。

#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
set<int>s;
set <int>::iterator ji; 
bitset<30005005>aa,bb;

void rua(int x,int v)
{
	int zz=v,l=v+1,r=0;
	while(x)
	{
		int ad=(x&1);
		zz++;
		if(ad)
		if(aa[zz])
			{
			    aa.set(zz,0);
			    x++;
			}
			else aa.set(zz,1);
		x>>=1;
	}
	r=zz;
	for1(i,l,r)
	{
		if(aa[i]^bb[i])
		    s.insert(i);
		else s.erase(i);
	}
}
void rub(int x,int v)
{
	int zz=v,l=v+1,r=0;
	while(x)
	{
		int ad=(x&1);
		zz++;
		if(ad)
			if(bb[zz])
			{
			    bb.set(zz,0);
		    	x++;
			}
			else bb.set(zz,1);
		x>>=1;
	}
	r=zz;
	for1(i,l,r)
	{
		if(aa[i]^bb[i])
		    s.insert(i);
		else 
		    s.erase(i);
	}
}
void add(int x,int v)
{
	if(x>0) 
	    rua(x,v);
	else 
	    rub(-x,v); 
	return ;
}
void ask(int x)
{
	int pd1,pd2;
	ji=s.lower_bound(x);
	ji--;
    pd1=(aa[x]^bb[x])? 1:0;
	pd2=(aa[*ji]<bb[*ji])? 1:0;
	if(pd1^pd2)
	puts("1");
	else
	puts("0");
}
int main()
{
    int n,t,a,b;
	cin>>n>>t>>t>>t;
	s.insert(0);
	s.insert(30*n+50);
	for1(i,1,n)
	{
		scanf("%d%d",&t,&a);
		if(t==1)
		{
			scanf("%d",&b);
			add(a,b);
		}
		else
			ask(++a);
	}
}
posted @ 2022-10-17 17:03  yyx525jia  阅读(29)  评论(0)    收藏  举报