提供一个来自 CF 大佬 adament 的有趣思路

首先我们知道的是一个只增加的 \(b\) 进制整数计数器,如果 \(b\) 是常数那么复杂度是均摊 \(O(1)\) 的。证明只需要考虑将 \(b\) 进制中为 \(b-1\) 的所有位的位数当成势能,那么每一次进位一定是 \(b-1\to 0\) 一定会消耗势能函数。

但这道题有加又有减,问题出在了可能有“退位” \(0\to b-1\),这时导致了势能函数的增加,这也是为什么均摊算法通常不能支持撤回。常规的做法是把加减分开考虑变成只加的情况。其实还有一种更简单的做法:我们不限制一个位上的值一定是 \([0,b)\) 的,而是 \((-b,b)\)。此时的进位/退位的形式都是 \(1-b\to 0\) 或 \(b-1 \to 0\)。我们将非零位的个数当成势能,这样进位/退位都会减小势能,而势能函数的总量就是 \(O(n)\) 的了。

然而现在要查询原数某一位,如何来还原原数的一位呢?我们发现进位对于下一位的影响总是 \(\pm 1\) 的,我们只需要找到我们当前查询的位的严格非零前驱,判断一下它是否为负,如果是当前位就需要 \(-1\) 然后输出。

具体到这题,我们需要将数 \(T\) 个压成一位,我实现压了 \(62\) 位。维护动态前驱用了 zkw 线段树上 finger search(只是减小常数)。输出时有个小技巧,负数的补码实际上就是它在二进制下的表示,所以提取负数的某一维可以直接跟正数一起位运算就可以了。

代码非常好写,跑得也飞快,复杂度 \(O(\frac{30n\log n}{T})\)。

#include <cstdio>
#include <bitset>
using namespace std;
int read(){
char c=getchar();int x=0;bool f=0;
while(c<48||c>57) f|=(c=='-'),c=getchar();
do x=(x<<1)+(x<<3)+(c^48),c=getchar();
while(c>=48&&c<=57);
if(f) return -x;
return x;
}
const int lT=62,sT=30;
typedef long long ll;
const ll Base=(1ll<<lT);
int q,dlt;
namespace ds{
bitset<1<<20> f;
void ins(int x){
x+=dlt;
while(!f[x]) f[x]=1,x>>=1;
}
void del(int x){
x+=dlt;
while(f[x]){
f[x]=0;
if(f[x^1]) return;
x>>=1;
}
}
int pre(int x){
if(!x) return -1;
x+=dlt-1;
if(f[x]) return x-dlt;
while(x>1){
if((x&1)&&f[x^1]) break;
x>>=1;
}
x^=1;
if(!x) return -1;
while(x<dlt){x<<=1;if(f[x^1]) x^=1;}
return x-dlt;
}
}
ll a[500003];
void upd(int x,ll v){
if(!v) return;
if(!a[x]) ds::ins(x);
a[x]+=v;
if(!a[x]) ds::del(x);
}
void inc(int x,int t){
bool sig=0;
if(x<0) sig=1,x=-x;
int bl=t/lT,wid=lT*(bl+1)-t;
if(wid>sT) wid=sT;
if(sig){
upd(bl,-((ll)(x&((1ll<<wid)-1))<<(t-bl*lT)));
upd(bl+1,-(x>>wid));
}
else{
upd(bl,(ll)(x&((1ll<<wid)-1))<<(t-bl*lT));
upd(bl+1,(x>>wid));
}
ll tmp=0;
int fl=0;
do{
upd(bl,tmp);
tmp=a[bl]/Base;
upd(bl,-Base*tmp);
++bl;++fl;
}while(fl<2||tmp);
}
bool qry(int x){
int bl=x/lT,p=ds::pre(bl);x%=lT;
if(p>=0&&a[p]<0) return (a[bl]-1)>>x&1;
else return a[bl]>>x&1;
}
int main(){
q=read();read();read();read();
for(dlt=1;dlt<=(q>>1)+1;dlt<<=1);
while(q--){
int op=read(),x=read();
if(op==1) inc(x,read());
else printf("%d\n",qry(x));
}
return 0;
}

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

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

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

  2. [NOI2017]整数

    [NOI2017]整数 题目大意: \(n(n\le10^6)\)次操作维护一个长度为\(30n\)的二进制整数\(x\),支持以下两种操作: 将这个整数加上\(a\cdot2^b(|a|\le10^ ...

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

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

  4. NOI2017整数

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

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

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

  6. Jenkins通过FTP上传站点太多文件导致太慢且不稳定,切换为压包上传再解压的思路(asp.net)

    在本地先处理好要上传的站点文件之后,可能会因为一些网页切图导致ftp上传不稳定,中断,或者文件占用的问题. 那么换了一种实现思路,要借助jenkins的工具jenkins-cli.jar. 解决思路: ...

  7. [Noi2017]整数 BZOJ4942

    分析: 30+暴力应该还是蛮水的,可以随便写写... 60+的就没那么容易了,但是应该挺裸的,往上架一颗线段树,查询连续1或0的长度,或者找到前缀中,第一个1或0,之后区间覆盖,单点查询,开bool, ...

  8. 工控安全入门(三)—— 再解S7comm

    之前的文章我们都是在ctf的基础上学习工控协议知识的,显然这样对于S7comm的认识还不够深刻,这次就做一个实战补全,看看S7comm还有哪些值得我们深挖的地方. 本篇是对S7comm的补全和实战,阅 ...

  9. 详解 LeetCode_007_整数反转(Java 实现)

    目录 LeetCode_007_整数反转 题目描述 总体分析 解决方案 小结 LeetCode_007_整数反转 题目描述 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示 ...

  10. 再解java中的String

    今天看到一篇文章中,写了关于java中的String.我看了后,是我从学java来觉得是最好的一篇关于String类的文章.看了这篇文章你就会对String的认识会提高一个层次.故将原作者的文章特意转 ...

随机推荐

  1. maven常用镜像源

    <mirrors> <mirror> <id>ibiblio</id> <mirrorOf>central</mirrorOf> ...

  2. jquery input标签的禁用和启用disabled

    input框使用disabled后 input 元素既不可用,也不可点击.可以设置 disabled 属性,直到满足某些其他的条件为止(比如选择了一个复选框等等).然后,就需要通过 JavaScrip ...

  3. 在Vim编辑器中查找选定文本

    按照任意选定文本查找: 1. 进入visiual模式选定文本, 按 y 键复制: 2. 按 / 键进入查找模式: 3. 按 Ctrl + r 打开vim寄存器: 4. 按 " 键将寄存器内容 ...

  4. Windows 下TCP长连接保持连接状态TCP keepalive设置

    TCP长连接建立完成后,我们通常需要检测网络的连接状态,以反馈给客户做响应的处理.通过设置TCP keepalive的属性,打开socket的keepalive属性,并设置发送底层心跳包的时间间隔.T ...

  5. 万字血书Vue—路由

    多个路由通过路由器进行管理. 前端路由的概念和原理 (编程中的)路由(router)就是一组key-value对应关系,分为:后端路由和前端路由 后端路由指的是:请求方式.请求地址和function处 ...

  6. Spark Catalyst 查询优化器原理

    这里我们讲解一下SparkSQL的优化器系统Catalyst,Catalyst本质就是一个SQL查询的优化器,而且和 大多数当前的大数据SQL处理引擎设计基本相同(Impala.Presto.Hive ...

  7. flex弹性盒子中flex-grow与flex的区别

    ​大家在使用flex布局的时候很多情况下都会用到flex-grow这个属性, flex-grow 属性用于设置父元素剩余空间的瓜分比例, flex 属性是 flex-grow.flex-shrink  ...

  8. XAML 设计器已意外退出。(退出代码: e0434352)

    一.前言 开门见山,这个问题我遇到过两次,第一次因为项目刚开始不长时间,我查了很长时间都没解决,然后就直接重写了,几乎一样的写法,但问题没复现了,但程序员思维告诉我,一定还是有比较关键的地方出现了问题 ...

  9. 手机号码归属地的自动查询.py(亲测有效)

    import requests url = "http://m.ip138.com/sj.asp?mobile=" kv = {'user-agent':'Mozilla/5.0' ...

  10. MySQL 中索引是如何实现的,有哪些类型的索引,如何进行优化索引

    MySQL 中的索引 前言 索引的实现 哈希索引 全文索引 B+ 树索引 索引的分类 聚簇索引(clustered index) 非聚簇索引(non-clustered index) 联合索引 覆盖索 ...