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;
}