[NOI2017] 整数

XL.[NOI2017] 整数

首先可以想到一种用线段树维护每一位的方法:一个数 \(a\times2^b\) 拆成 \(\log a\) 个位置上 \(+1\),执行单点 \(+1\) 的时候如果出现进位就找到右方第一个非 \(1\) 的位置,然后单点加,区间赋 \(0\);执行减法的时候,就是找到右方第一个非 \(0\) 的位置,单点减,然后区间赋 \(1\)。(总之就是手工高精度竖式计算之类的)

但是这样复杂度就是 \(O(n\log^2n)\),对于 \(10^6\) 不可能过。

然后,既然是高精度算法,那就可以压位,每 \(30\) 位压一块,这样执行一次加减法都不会爆 int。加法时就找到右方第一个非满的位置,减法时就找到右方第一个非零的位置,都可以线段树上二分简单维护。

时间复杂度 \(O(n\log n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int LG=30;
const int MD=1<<30;
int n;
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1) 
struct SegTree{
	int nz,nf,tag;//none-zero position,none-full position
	SegTree(){nz=nf=tag=-1;}
}seg[5001000];
#define LSON lson,l,mid
#define RSON rson,mid+1,r
#define X x,l,r
void MOD(int x,int l,int r,int y){if(!y)seg[x].nf=l,seg[x].nz=-1;if(y==MD-1)seg[x].nz=l,seg[x].nf=-1;seg[x].tag=y;}
void pushdown(int x,int l,int r){if(seg[x].tag!=-1)MOD(LSON,seg[x].tag),MOD(RSON,seg[x].tag),seg[x].tag=-1;}
void pushup(int x){if(seg[lson].nf!=-1)seg[x].nf=seg[lson].nf;else seg[x].nf=seg[rson].nf;if(seg[lson].nz!=-1)seg[x].nz=seg[lson].nz;else seg[x].nz=seg[rson].nz;}
void upd(int x,int l,int r){if(seg[x].tag)seg[x].nz=l;else seg[x].nz=-1;if(seg[x].tag!=MD-1)seg[x].nf=l;else seg[x].nf=-1;}
bool ADD(int x,int l,int r,int P,int y){
	if(l>P||r<P)return false;
	if(l==r){seg[x].tag+=y;bool ret=false;if(seg[x].tag>=MD)seg[x].tag-=MD,ret=true;upd(X);return ret;}
	pushdown(X);bool ret=ADD(LSON,P,y)||ADD(RSON,P,y);pushup(x);return ret;
}
bool SUB(int x,int l,int r,int P,int y){
	if(l>P||r<P)return false;
	if(l==r){seg[x].tag-=y;bool ret=false;if(seg[x].tag<0)seg[x].tag+=MD,ret=true;upd(X);return ret;}
	pushdown(X);bool ret=SUB(LSON,P,y)||SUB(RSON,P,y);pushup(x);return ret;
}
bool ADD1(int x,int l,int r,int P){
	if(r<=P)return false;
	if(l>P&&seg[x].nf==-1){MOD(X,0);return false;}
	if(l==r){seg[x].tag++,upd(X);return true;}
	pushdown(X);bool ret=ADD1(LSON,P)||ADD1(RSON,P);pushup(x);return ret;
}
bool SUB1(int x,int l,int r,int P){
	if(r<=P)return false;
	if(l>P&&seg[x].nz==-1){MOD(X,MD-1);return false;}
	if(l==r){seg[x].tag--,upd(X);return true;}
	pushdown(X);bool ret=SUB1(LSON,P)||SUB1(RSON,P);pushup(x);return ret;
}
void build(int x,int l,int r){if(l==r)seg[x].tag=0,seg[x].nf=l;else build(LSON),build(RSON),pushup(x);}
bool query(int x,int l,int r,int P,int k){if(l>P||r<P)return false;if(l==r)return (seg[x].tag>>k)&1;pushdown(X);return query(LSON,P,k)||query(RSON,P,k);}
void ADD(int a,int p){if(ADD(1,0,n+10,p,a))ADD1(1,0,n+10,p);}
void SUB(int a,int p){if(SUB(1,0,n+10,p,a))SUB1(1,0,n+10,p);}
void modify(int a,int b){
	if(!a)return;
	bool sub=false;if(a<0)a=-a,sub=true;
	int p=b/LG;b%=LG;
	ll A=((ll)a)<<b;
//	printf("%lld %d %d\n",A,p,b);
	if(!sub){ADD(A%MD,p);if(A>=MD)ADD(A/MD,p+1);}
	else{SUB(A%MD,p);if(A>=MD)SUB(A/MD,p+1);}
}
bool query(int p){return query(1,0,n+10,p/LG,p%LG);}
int read(){
	int x=0,fl=1;char c=getchar();
	for(;c>'9'||c<'0';c=getchar())if(c=='-')fl=-fl;
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return fl==1?x:-x;
}
void iterate(int x,int l,int r){if(l==r)printf("%d ",seg[x].tag);else pushdown(X),iterate(LSON),iterate(RSON);}
int main(){
//	freopen("integer3.in","r",stdin);
	n=read(),read(),read(),read();
	build(1,0,n+10);
//	iterate(1,0,n+10),puts("");
	for(int i=1,tp,a,b;i<=n;i++){
		tp=read(),a=read();
		if(tp==1)b=read(),modify(a,b);
		else printf("%d\n",query(a));
//	iterate(1,0,n+10),puts("");
	}
	return 0;
}

posted @ 2021-04-02 23:07  Troverld  阅读(91)  评论(0编辑  收藏  举报