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\).\ ...
随机推荐
- 使用json传输数组实例
client.php <?php //遍历数组元素,并将元素转码 function array_iconv($data, $in_charset='GBK', $out_charset='UTF ...
- Ionic开发-如何在ion-content形成上下结构 上面固定下层可滚动
在一个系统设计中,一般有些需要固定位置,便利操作.现在我要做一个上下两层,需要固定上方,下方拉刷新数据. 页面: <ion-content scroll="false"> ...
- 【前端】html5获取经纬度,百度api获取街区名,并使用JS保存进cookie
引用js<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak= ...
- 【转】深入理解Android中的SharedPreferences
SharedPreferences作为Android中数据存储方式的一种,我们经常会用到,它适合用来保存那些少量的数据,特别是键值对数据,比如配置信息,登录信息等.不过要想做到正确使用SharedPr ...
- XML验证
合法的XML和形式良好的XML ? 拥有正确语法的 XML 被称为"形式良好"的 XML. 第一行是 XML 声明.它定义 XML 的版本 (1.0) 和所使用的编码 (ISO-8 ...
- windows session logoff时进行处理动作
目标:Windows session logoff时得到通知,进行一些记录/清理工作 测试平台: win7 x64 logoff时系统会发送WM_ENDSESSION消息,如果某个应用对这个消息的处理 ...
- 进程池_Pool
当需要创建子进程数量不多的时候,可以直接利用multiprocessing中的Process动态生成多个进程 但是如果是成百甚至上千个任务,手动地创建它的工作量很大,此时就可以利用到multiproc ...
- .NET多线程总结
1.不需要传递参数,也不需要返回参数 我们知道启动一个线程最直观的办法是使用Thread类,具体步骤如下: public void test() { ThreadStart threadStart = ...
- OPENCV3 命名空间等变化
CV_VERSION 表示的opencv的版本号 命名空间变化: 可以通过增加 #include <cv.h> 解决 1 直接去掉CV_ 前缀 1) nameWindow 函数 C ...
- 【2019-5-26】python:字典、常用字符串处理方法及文件操作
一.数据类型:字典 1.字典: 1.1定义字典:dict={'key':'value'} 1.2字典与列表相比,字典取值快,可直接找到key 1.3字典是无序的,不能根据顺序取值 1.4多个元素用逗号 ...