LibreOJ2302 - 「NOI2017」整数
Description
有一个整数\(x=0\),对其进行\(n(n\leq10^6)\)次操作:
- 给出\(a(|a|\leq10^9),b(b\leq30n)\),将\(x\)加上\(a\cdot 2^b\)。
- 询问\(x\)在二进制下位权为\(2^k(k\leq30n)\)的位的值。
保证任意时刻\(x\geq0\)。
Solution
用线段树来模拟二进制下的加减运算。
线段树上的每个位置维护\(30\)位二进制数,即第一位维护\(2^0...2^{29}\),第二位维护\(2^{30}...2^{59}\),以此类推。考虑当我们将某位置上的值修改为\(a\)后应当怎么做:
- 若\(a\in[0,2^{30})\),则什么也不做。
- 若\(a\geq2^{30}\),则需要进位:将前面一段连续的\(2^{30}-1\)修改为\(0\),然后将这段\(2^{30}-1\)前面的一个数\(+1\)。
- 若\(a<0\),则需要退位:将前面一段连续的\(0\)修改为\(2^{30}-1\),然后将这段\(0\)前面的一个数\(-1\)。
那么我们需要区间修改,单点查询,并维护每个区间从低位到高位连续的\(0/2^{30}-1\)的长度。具体细节可以看代码。
时间复杂度\(O(nlogn)\)。
Code
//「NOI2017」整数
#include <cstdio>
#include <cstring>
inline char gc()
{
static char now[1<<16],*s,*t;
if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
return *s++;
}
inline int read()
{
int x=0,f=1; char ch=gc();
while(ch<'0'||'9'<ch) f=(ch^'-')?f:-1,ch=gc();
while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int const N=4e6+10;
int const N0=30;
int n=1e6+100;
int Q,t1,t2,t3;
#define Ls (p<<1)
#define Rs ((p<<1)|1)
int rt,len[2][N],val[N],tag[N];
void update(int p,int L0,int R0)
{
int mid=L0+R0>>1;
len[0][p]=len[0][Ls]+(len[0][Ls]==mid-L0+1)*len[0][Rs];
len[1][p]=len[1][Ls]+(len[1][Ls]==mid-L0+1)*len[1][Rs];
}
void change(int p,int L0,int R0,int x)
{
if(x) val[p]=(1<<N0)-1; else val[p]=0;
tag[p]=x,len[x][p]=R0-L0+1,len[x^1][p]=0;
}
void pushdw(int p,int L0,int R0)
{
if(tag[p]<0) return;
int mid=L0+R0>>1;
change(Ls,L0,mid,tag[p]),change(Rs,mid+1,R0,tag[p]);
tag[p]=-1;
}
int L,R,cyV;
void ins1(int p,int L0,int R0,int v)
{
if(L<=L0&&R0<=R)
{
val[p]+=v;
if(val[p]>=(1<<N0)) cyV=1,val[p]&=(1<<N0)-1;
if(val[p]<0) cyV=0,val[p]+=1<<N0;
len[0][p]=len[1][p]=0;
if(val[p]==0) len[0][p]=1;
if(val[p]==(1<<N0)-1) len[1][p]=1;
return;
}
pushdw(p,L0,R0);
int mid=L0+R0>>1;
if(L<=mid) ins1(Ls,L0,mid,v);
if(mid<R) ins1(Rs,mid+1,R0,v);
update(p,L0,R0);
}
void ins2(int p,int L0,int R0,int v)
{
if(L<=L0&&R0<=R) {change(p,L0,R0,v); return;}
pushdw(p,L0,R0);
int mid=L0+R0>>1;
if(L<=mid) ins2(Ls,L0,mid,v);
if(mid<R) ins2(Rs,mid+1,R0,v);
update(p,L0,R0);
}
int query1(int p,int L0,int R0)
{
if(L<=L0&&R0<=R) return val[p];
pushdw(p,L0,R0);
int mid=L0+R0>>1;
if(L<=mid) return query1(Ls,L0,mid);
if(mid<R) return query1(Rs,mid+1,R0);
}
//query2返回在[L0,R0]∩[L,R]中L向后有多少个连续的v
int query2(int p,int L0,int R0,int v)
{
if(L<=L0&&R0<=R) return len[v][p];
pushdw(p,L0,R0);
int mid=L0+R0>>1,r1=0,r2=0;
if(L<=mid) r1=query2(Ls,L0,mid,v);
if(mid<R) r2=query2(Rs,mid+1,R0,v);
if(L<=mid) return r1+(r1==mid-L+1)*r2;
else return r2;
}
void add(int x,int v)
{
L=R=x,cyV=-1; ins1(rt,1,n,v);
if(cyV>=0)
{
L=x+1,R=n; int len=query2(rt,1,n,cyV);
L=x+1,R=x+len; if(L<=R) ins2(rt,1,n,cyV^1);
L=R=x+len+1; ins1(rt,1,n,cyV?1:-1);
}
}
int main()
{
Q=read(); t1=read(),t2=read(),t3=read();
memset(tag,-1,sizeof tag);
rt=1;
change(rt,1,n,0);
for(int i=1;i<=Q;i++)
{
int opt=read();
if(opt==1)
{
int a=read(),b=read();
int b1=b/N0+1,b2=b%N0,t=1<<(N0-b2);
int a1=a/t,a2=a%t*(1<<b2);
add(b1,a2); add(b1+1,a1);
}
else
{
int k=read();
int k1=k/N0+1,k2=k%N0;
L=R=k1; printf("%d\n",(query1(rt,1,n)>>k2)&1);
}
}
return 0;
}
P.S.
多谢Pickupwin大佬指点
LibreOJ2302 - 「NOI2017」整数的更多相关文章
- 「NOI2017」整数 解题报告
「NOI2017」整数 有一些比较简单的\(\log^2n\)做法 比如暴力在动态开点线段树上维护每个位置为\(0\)还是\(1\),我们发现涉及到某一位加上\(1\)或者减去\(1\)实际上对其他位 ...
- LOJ2302 「NOI2017」整数
「NOI2017」整数 题目背景 在人类智慧的山巅,有着一台字长为$1048576$位(此数字与解题无关)的超级计算机,著名理论计算机科 学家P博士正用它进行各种研究.不幸的是,这天台风切断了电力系统 ...
- LOJ#2302. 「NOI2017」整数
$n \leq 1000000$个操作:一,给$x$加上$a*2^b$:二,问$x$的某个二进制位$k$.$b,k \leq 30n$,$|a| \leq 1e9$. 30暴露了一切..可以把30个二 ...
- LOJ 2302 「NOI2017」整数——压位线段树
题目:https://loj.ac/problem/2302 压30位,a最多落在两个位置上,拆成两次操作. 该位置加了 a 之后,如果要进位或者借位,查询一下连续一段 0 / 1 ,修改掉,再在含有 ...
- loj #2305. 「NOI2017」游戏
#2305. 「NOI2017」游戏 题目描述 小 L 计划进行 nnn 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 AAA.BBB. ...
- LOJ2305 「NOI2017」游戏
「NOI2017」游戏 题目背景 狂野飙车是小 L 最喜欢的游戏.与其他业余玩家不同的是,小 L 在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略. 题目描述 小 L 计划进行$n$场 ...
- LOJ2303 「NOI2017」蚯蚓排队
「NOI2017」蚯蚓排队 题目描述 蚯蚓幼儿园有$n$只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从$1$到$n$的连续正整数编号.每只蚯蚓的长度可以用一个正整数表示 ...
- LOJ_2305_「NOI2017」游戏 _2-sat
LOJ_2305_「NOI2017」游戏 _2-sat 题意: 给你一个长度为n的字符串S,其中第i个字符为a表示第i个地图只能用B,C两种赛车,为b表示第i个地图只能用A,C两种赛车,为c表示第i个 ...
- 「NOI2017」游戏
「NOI2017」游戏 题目描述 小 L 计划进行 \(n\) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 \(A\).\(B\).\ ...
随机推荐
- css3 blur模糊解决ie6-ie9兼容
css3 blur模糊是css3的新特性,但是不兼容ie6-ie9,以下代码可以解决此问题: filter: progid:DXImageTransform.Microsoft.Blur(Pixel ...
- iOS圆形图片裁剪,原型图片外面加一个圆环
/** * 在圆形外面加一个圆环 */ - (void)yuanHuan{ //0.加载图片 UIImage *image = [UIImage imageNamed:@"AppIcon1 ...
- Android模板制作
本文详细介绍模板相关的知识和如何制作Android模版及使用,便于较少不必要的重复性工作.比如我在工作中如果要创建一个新的模块,就不要需要创建MVP相关的几个类:Model.View.Presente ...
- Java 利用FTP上传,下载文件,遍历文件目录
Java实现FTP上传下载文件的工具包有很多,这里我采用Java自带的API,实现FTP上传下载文件.另外JDK1.7以前的版本与其之后版本的API有了较大的改变了. 例如: JDK1.7之前 JDK ...
- sqlserver:查询锁住sql以及解锁
--查看被锁表:SELECT request_session_id spid, OBJECT_NAME( resource_associated_entity_id ) tableNameFROM s ...
- Angular和SAP C4C的事件处理队列
Angular 我们在Angular框架的代码里能看到一个名为processQueue的函数: 这个函数是通过$scope.$apply启动的: 核心代码位于一个for循环里,循环体是一个存储异步处理 ...
- 原创:PHP编译安装配置参数说明
--prefix=/application/php-5.5.32 \ #指定PHP的安装路径 --with-mysql=/application/mysql/ \ ...
- SQLite_安装
SQLite -安装 zero-configuration SQLite闻名的特性,这意味着不需要复杂的设置或管理.本章将带你通过设置SQLite的过程在Windows.Linux和Mac OS X. ...
- zabbix设置多个收件人
1.建群组 2.添加群组权限 3.添加用户,归属到上面新建的组 4.动作里发送消息给新建的组 5.这样设置后,管理员账号不用设置收件媒介
- C++ isalpha、isalnum、islower、isupper用法
1. isalpha isalpha()用来判断一个字符是否为字母,如果是字符则返回非零,否则返回零. cout<<isalpha('a'); //返回非零 cout<<isa ...