[NOI2017]整数

题目大意:

\(n(n\le10^6)\)次操作维护一个长度为\(30n\)的二进制整数\(x\),支持以下两种操作:

  1. 将这个整数加上\(a\cdot2^b(|a|\le10^9,b\le30)\)。
  2. 询问这个整数第\(k\)位的值。

题目保证任何时刻\(x\ge0\)。

思路:

维护每一位的值,并在线段树上记录每个区间是否含有\(0\)或\(1\),以便发生进退位时快速查找到进退位结束的位置。区间修改,单点查询。时间复杂度\(\mathcal O(n\log(30n))\)。显然会TLE。

考虑使用压位线段树,每\(30\)位压在一个叶子结点,修改操作可以枚举\(a\)的每一个二进制位\(1\)并进行相应的操作。由于\(a\)最多有\(\log a\)个二进制位,因此时间复杂度\(\mathcal O(n\log n\log a)\)。实测\(76\)分。

事实上,由于\(a\)在线段树中最多对应\(2\)个叶子结点,而叶子结点内部的进位就是整数加减法,不需要专门在线段树上查找。我们可以直接将\(a\)拆分成两次修改,时间复杂度\(\mathcal O(n\log n)\)。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
register bool neg=false;
while(!isdigit(ch=getchar())) neg|=ch=='-';
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return neg?-x:x;
}
const int N=1e6,base=30,lim=(1<<base)-1;
typedef long long int64;
int n;
inline int bel(const int &x) {
return x/base+1;
}
class SegmentTree {
#define _left <<1
#define _right <<1|1
#define mid ((b+e)>>1)
private:
bool have[2][N<<2];
int val[N],tag[N<<2];
void push_up(const int &p) {
have[0][p]=have[0][p _left]||have[0][p _right];
have[1][p]=have[1][p _left]||have[1][p _right];
}
void push_down(const int &p,const int &b,const int &e) {
if(tag[p]==-1) return;
b==mid?val[b]=lim*tag[p]:tag[p _left]=tag[p];
mid+1==e?val[e]=lim*tag[p]:tag[p _right]=tag[p];
have[tag[p]][p _left]=have[tag[p]][p _right]=true;
have[!tag[p]][p _left]=have[!tag[p]][p _right]=false;
tag[p]=-1;
}
public:
void build(const int &p,const int &b,const int &e) {
tag[p]=-1;
have[0][p]=true;
if(b==e) return;
build(p _left,b,mid);
build(p _right,mid+1,e);
}
int find(const int &p,const int &b,const int &e,const int &x,const bool &t) {
if(!have[t][p]) return 0;
if(b==e) {
const int tmp=(t?val[b]:~val[b])>>(bel(x)!=b?0:x%base);
if(tmp==0) return 0;
const int pos=__builtin_ffs(tmp)-1+(bel(x)!=b?0:x%base);
return pos<base?pos+(b-1)*base+1:0;
}
push_down(p,b,e);
if(bel(x)<=mid) {
return find(p _left,b,mid,x,t)?:find(p _right,mid+1,e,x,t);
} else {
return find(p _right,mid+1,e,x,t);
}
}
void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const bool &t) {
if(tag[p]==t) return;
if(b==e) {
if(!t) val[b]=~val[b];
val[b]|=(1<<(r%base+1))-(1<<(l%base));
if(!t) val[b]=~val[b];
have[0][p]=lim-val[b];
have[1][p]=val[b];
return;
}
if(l==(b-1)*base&&r==e*base-1) {
tag[p]=t;
have[!t][p]=false;
have[t][p]=true;
return;
}
push_down(p,b,e);
if(bel(l)<=mid) modify(p _left,b,mid,l,std::min(mid*base-1,r),t);
if(bel(r)>mid) modify(p _right,mid+1,e,std::max(mid*base,l),r,t);
push_up(p);
}
void change(const int &p,const int &b,const int &e,const int &x,const bool &t) {
if(tag[p]==t) return;
if(b==e) {
val[b]^=1<<(x%base);
have[0][p]=lim-val[b];
have[1][p]=val[b];
return;
}
push_down(p,b,e);
if(bel(x)<=mid) change(p _left,b,mid,x,t);
if(bel(x)>mid) change(p _right,mid+1,e,x,t);
push_up(p);
}
bool query(const int &p,const int &b,const int &e,const int &x) {
if(!have[0][p]) return 1;
if(!have[1][p]) return 0;
if(b==e) return val[b]>>(x%base)&1;
return bel(x)<=mid?query(p _left,b,mid,x):query(p _right,mid+1,e,x);
}
bool modify2(const int &p,const int &b,const int &e,const int &x,const int &y,const bool &t) {
if(b==e) {
t?val[b]-=y:val[b]+=y;
const bool ret=val[b]<0||val[b]>lim;
if(val[b]>lim) val[b]-=lim+1;
if(val[b]<0) val[b]+=lim+1;
have[0][p]=lim-val[b];
have[1][p]=val[b];
return ret;
}
push_down(p,b,e);
bool ret;
if(x<=mid) ret=modify2(p _left,b,mid,x,y,t);
if(x>mid) ret=modify2(p _right,mid+1,e,x,y,t);
push_up(p);
return ret;
}
#undef _left
#undef _right
#undef mid
};
SegmentTree t;
int main() {
n=getint();
getint(),getint(),getint();
t.build(1,1,n);
for(register int i=0;i<n;i++) {
const int opt=getint();
if(opt==1) {
int a=getint();
const int b=getint();
const bool v=a<0;
if(v) a=-a;
const int t1=(int64)a<<(b%30)&lim;
const int t2=(((int64)a<<(b%30))-((int64)a<<(b%30)&lim))>>base;
if(t.modify2(1,1,n,bel(b),t1,v)) {
const int pos=t.find(1,1,n,bel(b)*30,v)-1;
t.change(1,1,n,pos,v);
if(pos>bel(b)*30) t.modify(1,1,n,bel(b)*30,pos-1,v);
}
if(t.modify2(1,1,n,bel(b)+1,t2,v)) {
const int pos=t.find(1,1,n,(bel(b)+1)*30,v)-1;
t.change(1,1,n,pos,v);
if(pos>(bel(b)+1)*30) t.modify(1,1,n,(bel(b)+1)*30,pos-1,v);
}
}
if(opt==2) {
printf("%d\n",t.query(1,1,n,getint()));
}
}
return 0;
}

[NOI2017]整数的更多相关文章

  1. 【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

    [BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依 ...

  2. [Bzoj4942][Noi2017]整数(线段树)

    4942: [Noi2017]整数 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 363  Solved: 237[Submit][Status][D ...

  3. NOI2017整数

    NOI2017 整数 题意: ​ 让你实现两个操作: 1 \(a\) \(b\):将\(x\)加上整数\(a \cdot 2 ^ b\),其中 \(a\)为一个整数,\(b\)为一个非负整数 2 \( ...

  4. 【BZOJ4942】[NOI2017]整数(分块)

    [BZOJ4942][NOI2017]整数(分块) 题面 BZOJ 洛谷 题解 暴力就是真正的暴力,直接手动模拟进位就好了. 此时复杂度是模拟的复杂度加上单次询问的\(O(1)\). 所以我们需要优化 ...

  5. 【bzoj4942】[Noi2017]整数 压位+线段树

    题目描述 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 $x$ ,一开始为0. 接下来有 $n$ 个操作,每个操作都是以下两种类型中的一种: 1 a b :将 $x$ 加上整数 ...

  6. [BZOJ4942] [NOI2017]整数

    题目背景 在人类智慧的山巅,有着一台字长为1048576位(此数字与解题无关)的超级计算机,著名理论计算机科 学家P博士正用它进行各种研究.不幸的是,这天台风切断了电力系统,超级计算机 无法工作,而 ...

  7. BZOJ.4942.[NOI2017]整数(分块)

    BZOJ 洛谷 UOJ 可能是退役之前最后一个BZOJ rank1了? 参考这里. 如果没有减法,对一个二进制数暴力进位,均摊复杂度是\(O(1)\)的(要进\(O(n)\)次位就至少需要\(O(n) ...

  8. 洛谷3822 [NOI2017] 整数 【线段树】【位运算】

    题目分析: 首先这题的询问和位(bit)有关,不难想到是用线段树维护位运算. 现在我们压32位再来看这道题. 对于一个加法操作,它的添加位置可以得到,剩下的就是做不超过32的位移.这样根据压位的理论. ...

  9. BZOJ4942 NOI2017整数(线段树)

    首先把每32位压成一个unsigned int(当然只要压起来能过就行).如果不考虑进/退位的话,每次只要将加/减上去的数拆成两部分直接单点修改就好了.那么考虑如何维护进/退位.可以发现进位的过程其实 ...

随机推荐

  1. Coursera在线学习---第九节(2).推荐系统

    一.基于内容的推荐系统(Content Based Recommendations) 所谓基于内容的推荐,就是知道待推荐产品的一些特征情况,将产品的这些特征作为特征变量构建模型来预测.比如,下面的电影 ...

  2. pandas中DataFrame使用

    切片选择 #显示第一行数据print(df.head(1)) #显示倒数三行数据 print(df.tail(3)) loc  df.loc[row_index,col_index]  注意loc是根 ...

  3. vmware安装ubuntu " Intel VT-x 处于禁用状态"

    vmware安装ubuntu " Intel VT-x 处于禁用状态" http://jingyan.baidu.com/article/fc07f98976710e12ffe51 ...

  4. 使用IDA PRO+OllyDbg+PEview 追踪windows API 动态链接库函数的调用过程

    使用IDA PRO+OllyDbg+PEview 追踪windows API 动态链接库函数的调用过程 http://blog.csdn.net/liujiayu2/article/details/5 ...

  5. 关于进度管理工具Gantt图

    关于进度管理工具Gantt图 18.以下关于进度管理工具图的叙述中,不正确的是( D). A.能清晰地表达每个任务的开始时间.结束时间和持续时间 B.能清晰地表达任务之间的并行关系 C.不能清晰地确定 ...

  6. LinkedList 源码分析

    LinkedList :双向链表结构, 内部存在frist节点 和 last节点.通过改变 首节点和 尾节点的引用来实现新增和修改 有一个内部类: //节点类,内部包括前节点和后节点,和数据项 // ...

  7. hdu 2227(树状数组+dp)

    Find the nondecreasing subsequences Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/3 ...

  8. NYOJ 10 skiing(好题)

    skiing 时间限制:3000 ms  |  内存限制:65535 KB 难度:5   描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当 ...

  9. JMeter------ _time 函数的使用(时间戳、当前时间)

    操作步骤: 1.通过函数助手,生成一个_time 函数: 2.如果参数为时间戳,那公式为: ${__time(,)}  :  默认该公式精确到毫秒级别, 13位数 ${__time(/1000,)}  ...

  10. 前端读者 | 从一行代码里面学点JavaScript

    本文来自 @张小俊128:链接:http://www.html-js.com/article/A-day-to-learn-from-a-line-of-code-inside-the-JavaScr ...