Luogu P3822 [NOI2017]整数

被陈指导秒掉的一眼题,然而我需要接受陈指导的指导才会做

首先根据经典的势能分析,直接暴力做加法复杂度其实是对的,每一位的贡献是\(O(1)\)级别的

而且这里的\(30n\)的数据范围也印证了这一点,我们直接暴力压位即可

但是这种做法显然不支持撤销,因此减法的时候就会直接GG

我们考虑分别维护出加上的数的和以及减去的数的和

考虑求第\(k\)位,容易发现我们此时只要判断\([0,k)\)位会不会出现借位即可

显然我们只需要找到小于\(k\)的第一个不相同的位置即可,用set维护所有不相同的位置即可实现

复杂度\(O(30n+n\log n)\)

#include<cstdio>
#include<set>
#include<cctype>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define int long long
using namespace std;
typedef set <int>:: iterator SI;
const int N=1000005,S=(1LL<<32)-1;
int n,opt,x,y,a[N],b[N]; set <int> s;
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() ((A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin)),A==B)?EOF:*A++)
		char Fin[S],*A,*B;
	public:
		Tp inline void read(T& x)
		{
			x=0; char ch; int flag=1; while (!isdigit(ch=tc())) if (ch=='-') flag=-1;
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); x*=flag;
		}
		#undef tc 
}F;
inline void reset(int *a,int *b,CI p)
{
	if (a[p]!=b[p]) { if (!s.count(p)) s.insert(p); }
	else { if (s.count(p)) s.erase(p); }
}
inline void add(int *a,int *b,CI x,CI y)
{
	int p=y>>5,q=y&31; a[p]+=(1LL<<q)*x; a[p+1]+=(a[p]>>32); a[p]&=S; reset(a,b,p); ++p;
	while (a[p]>S) a[p+1]+=(a[p]>>32),a[p]&=S,reset(a,b,p),++p; reset(a,b,p);
}
inline int query(CI x)
{
	int p=x>>5,q=x&31,tp=((a[p]>>q)^(b[p]>>q))&1;
	int la=a[p]&((1LL<<q)-1),lb=b[p]&((1LL<<q)-1);
	if (la!=lb) return tp^(la<lb); SI pos=s.lower_bound(p);
	if (pos==s.begin()) return tp; return --pos,tp^(a[*pos]<b[*pos]);
}
signed main()
{
	for (F.read(n),F.read(x),F.read(x),F.read(x);n;--n)
	{
		F.read(opt); F.read(x);	if (opt==1)
		{ if ( F.read(y),x>0) add(a,b,x,y); else add(b,a,-x,y); }
		else putchar(query(x)?'1':'0'),putchar('\n');
	}
	return 0;
}
posted @ 2020-11-30 16:51  空気力学の詩  阅读(134)  评论(0编辑  收藏  举报