[NOI2017] 整数

XL.[NOI2017] 整数

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

但是这样复杂度就是 O(nlog2n),对于 106 不可能过。

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

时间复杂度 O(nlogn)

代码:

#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 @   Troverld  阅读(99)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示