首先把每32位压成一个unsigned int(当然只要压起来能过就行)。如果不考虑进/退位的话,每次只要将加/减上去的数拆成两部分直接单点修改就好了。那么考虑如何维护进/退位。可以发现进位的过程其实就是将一段连续的inf改为0,并把之后一位+1,也就是说只要找到某一位之后第一个不是inf的位就好了。我们用线段树维护这个东西,记录一下某个节点表示的区间是否全为inf。查询时先从叶子节点往上爬,直到当前节点代表的区间中在该叶子节点右边的位不全为inf时停止,之后再往下找最左的非inf位。退位类似。这样的话复杂度就是O(nlogn)。

  写起来挺烦的,注意一下各种细节,码力极弱选手表示调了快一天……惨惨。

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 1000010
#define ui unsigned int
#define inf 4294967295
#define lson (k<<1)
#define rson (k<<1|1)
#define getmid; int mid=tree[k].l+tree[k].r>>1;
int n;
struct data{int l,r,tag,size,sumzero,suminf;ui num;
}tree[N<<];
bool isleaf(int k){return tree[k].size==;}
void build(int k,int l,int r)
{
tree[k].l=l,tree[k].r=r,tree[k].size=r-l+;
tree[k].sumzero=tree[k].size,tree[k].suminf=;
if (isleaf(k)) return;
getmid;
build(lson,l,mid);
build(rson,mid+,r);
}
void up(int k)
{
tree[k].sumzero=tree[lson].sumzero+tree[rson].sumzero;
tree[k].suminf=tree[lson].suminf+tree[rson].suminf;
}
void update(int k,int tag)
{
if (tag>) tree[k].sumzero=tree[k].size,tree[k].suminf=;
else tree[k].sumzero=,tree[k].suminf=tree[k].size;
tree[k].tag=tag;
if (isleaf(k)) tree[k].num=tag>?:inf;
}
void down(int k)
{
if (tree[k].tag)
{
update(lson,tree[k].tag);
update(rson,tree[k].tag);
tree[k].tag=;
}
}
int find(int k,int x)
{
if (isleaf(k)) return k;
down(k);
getmid;
int ans;
if (x<=mid) ans=find(lson,x);
else ans=find(rson,x);
up(k);
return ans;
}
void modify(int k,int l,int r,int tag)
{
if (tree[k].l==l&&tree[k].r==r)
{
update(k,tag);
return;
}
down(k);
getmid;
if (r<=mid) modify(lson,l,r,tag);
else if (l>mid) modify(rson,l,r,tag);
else modify(lson,l,mid,tag),modify(rson,mid+,r,tag);
up(k);
}
int add(int k,int p,ui x)
{
if (isleaf(k))
{
int v=inf-tree[k].num<x;
tree[k].num+=x;
tree[k].sumzero=(tree[k].num==);
tree[k].suminf=(tree[k].num==inf);
return v;
}
down(k);
getmid;
int ans;
if (p<=mid) ans=add(lson,p,x);
else ans=add(rson,p,x);
up(k);
return ans;
}
int dec(int k,int p,ui x)
{
if (isleaf(k))
{
int v=tree[k].num<x;
tree[k].num-=x;
tree[k].sumzero=(tree[k].num==);
tree[k].suminf=(tree[k].num==inf);
return v;
}
down(k);
getmid;
int ans;
if (p<=mid) ans=dec(lson,p,x);
else ans=dec(rson,p,x);
up(k);
return ans;
}
void pushup(int k)
{
if (tree[k].suminf)
{
int t=k,cnt=;
while (tree[k].suminf-cnt==tree[k].r-tree[t].l+)
{
if (k&) cnt+=tree[k-].suminf;
k>>=;
}
k=rson;
while (!isleaf(k))
{
down(k);
if (tree[lson].suminf==tree[lson].size) k=rson;
else k=lson;
}
modify(,tree[t].l,tree[k].l-,);
}
add(,tree[k].l,);
}
void pushdown(int k)
{
if (tree[k].sumzero)
{
int t=k,cnt=;
while (tree[k].sumzero-cnt==tree[k].r-tree[t].l+)
{
if (k&) cnt+=tree[k-].sumzero;
k>>=;
}
k=rson;
while (!isleaf(k))
{
down(k);
if (tree[lson].sumzero==tree[lson].size) k=rson;
else k=lson;
}
modify(,tree[t].l,tree[k].l-,-);
}
dec(,tree[k].l,);
}
int query(int k,int p,int x)
{
if (isleaf(k)) return tree[k].num>>x&;
down(k);
getmid;
int ans;
if (p<=mid) ans=query(lson,p,x);
else ans=query(rson,p,x);
up(k);
return ans;
}
int main()
{
n=read();read(),read(),read();
build(,,n+);
for (int i=;i<=n;i++)
{
int op=read();
if (op==)
{
int x=read(),y=read();
if (x>)
{
ui v=x;
ui a=v<<(y&),b=(y&)?(v>>(-(y&))):;
if (a>) b+=add(,(y>>)+,a);
if (b>)
{
a=add(,(y>>)+,b);
if (a>) pushup(find(,(y>>)+));
}
}
else
{
ui v=abs(x);
ui a=v<<(y&),b=(y&)?(v>>(-(y&))):;
if (a>) b+=dec(,(y>>)+,a);
if (b>)
{
a=dec(,(y>>)+,b);
if (a>) pushdown(find(,(y>>)+));
}
}
}
else
{
int x=read();
printf("%d\n",query(,(x>>)+,x&));
}
}
return ;
}

BZOJ4942 NOI2017整数(线段树)的更多相关文章

  1. [BZOJ4942][Noi2017]整数 线段树+压位

    用线段树来模拟加减法过程,维护连续一段中是否全为0/1. 因为数字很大,我们60位压一位来处理. #include<iostream> #include<cstring> #i ...

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

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

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

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

  4. 2018.10.30 bzoj4942: [Noi2017]整数(线段树压位)

    传送门 直接把修改的数拆成logloglog个二进制位一个一个修改是会TLETLETLE的. 因此我们把303030个二进制位压成一位储存在线段树里面. 然后维护区间中最靠左二进制位不为0/1的下标. ...

  5. UOJ #314. 【NOI2017】整数 | 线段树 压位

    题目链接 UOJ 134 题解 可爱的电音之王松松松出的题--好妙啊. 首先想一个朴素的做法! 把当前的整数的二进制当作01序列用线段树维护一下(序列的第i位就是整数中位权为\(2^k\)的那一位). ...

  6. noi2017 T1 整数 ——线段树

    loj.ac上有  题目传送门 不过我还是把题目搬过来吧 整数(integer)[题目背景]在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行 ...

  7. BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流

    题目链接: [Noi2017]蔬菜 题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量), ...

  8. 【noi2017】 整数 线段树or模拟

    ORZYYB 题目大意:你需要维护一个有$3\times 10^7$个二进制位的数,有一种修改方式和一种询问方式 对这个数加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times ...

  9. [BZOJ4942] [NOI2017]整数

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

随机推荐

  1. SkylineGlobe 如何二次开发实现天际线分析功能

    天际线效果: 示例代码: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <h ...

  2. NPOI DataSet导出excel

    /// <summary> /// DataSet导出到Excel的MemoryStream /// </summary> /// <param name="d ...

  3. 如何让.NET Core支持GB2312和GBK

    在.NET Core中,默认是不支持GB2312和GBK编码的. 例如我们如果新建一个.NET Core控制台项目,然后在其Main方法中使用如下代码: using System; using Sys ...

  4. SessionState in ASP.NET Core(转载)

    问: In asp.net mvc we used to decorate controller for disabling session state by using attribute as [ ...

  5. 如何实现.net程序的进程注入

    原文:如何实现.net程序的进程注入   如何实现.net程序的进程注入                                   周银辉 进程注入比较常见,比如用IDE调试程序以及一些Sp ...

  6. Scala学习(七)---包和引入

    包和引入 摘要: 在本篇中,你将会了解到Scala中的包和引入语句是如何工作的.相比Java不论是包还是引入都更加符合常规,也更灵活一些.本篇的要点包括: 1. 包也可以像内部类那样嵌套 2. 包路径 ...

  7. Nancy异步用法

    个人笔记,记录Nancy异步用法 基类,所有请求都将首先执行该类,并执行Before事件 namespace CxyAdvert.Base { public class BaseNancyModel ...

  8. for循环两个略骚的写法

    骚写法 或许你知道,总之我觉得很酷,希望你也这么认为. 递增遍历 最常见场景,从 0 到 10 的遍历,不输出 10: for(let i = -1; ++i < 10;) { console. ...

  9. CSharp 案例:用 Dynamic 来解决 DataTable 数值累加问题

    需求说明 给定一个 DataTable,如果从中取出数值类型列的值并对其累加? 限制:不知该列是何种数值类型. 解决方案 1.将表转换为 IEnumerable<dynamic>,而后获取 ...

  10. rsync同步时,删除目标目录比源目录多余文件的方法(--delete)

    在日常运维工作中,我们经常用到rsync这个同步神器.有时在同步两个目录时,会要求删除目标目录中比源目录多出的文件,这种情况下,就可用到rsync的--delete参数来实现这个需求了. 实例说明:在 ...