【NOI】2017 整数(BZOJ 4942,LOJ2302) 压位+线段树
【题目】#2302. 「NOI2017」整数
【题意】有一个整数x,一开始为0。n次操作,加上a*2b,或询问2k位是0或1。\(n \leq 10^6,|a| \leq 10^9,0 \leq b,k \leq 30n\)。
【算法】压位+线段树
【参考】GXZlegend
先考虑以每一位为下标开线段树,将一次加减法拆成log a次一个位的加减法。
考虑对位x加法,如果x为0直接加,如果x为1则向高位找到第一个0加上1,然后之间的区间全部置为0。
减法同理,如果x为1直接减,否则向高位找到第一个1减去,然后区间置1。
线段树维护区间是否全为0/1,复杂度\(O(30n \ \ log^2n)\)(log后面的数字不深究)。
考虑优化,每一位只记录0/1太浪费了,考虑每一位用int记录30位(数据范围有提示作用),这样每次加减就变成两个位的加减了。
按照上面的思路对位x加法,如果\(x<2^{30}-1\)直接加,否则向高位找到第一个满足\(x<2^{30}-1\)的数字加上,区间置为0。减法同理。
复杂度\(O(n \ \ log \ \ n)\)。
注意:
1.每次将修改前后两位数字的方法是分割后和\(2^{30}-1\)取与。
2.线段树二分:①整个区间是否可以跳过,②是否到了叶子,③尝试往左区间,不行再往右区间。
3.重点关注标记的传递,很容易写错。
4.这种题似乎只能静态差错……
#include<cstdio>
#include<cstring>
#include<algorithm>
bool isdigit(char c){return c>='0'&&c<='9';}
int read(){
int s=0,t=1;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-1;
do{s=s*10+c-'0';}while(isdigit(c=getchar()));
return s*t;
}
using namespace std;
const int maxn=1000020,N=1000010,mx=(1<<30)-1,S=(1<<30);
int n,t1,t2,t3;
bool ok;
struct tree{int l,r,c,d,num;}t[maxn*4];
void up(int k){if(t[k<<1].c==t[k<<1|1].c)t[k].c=t[k<<1].c;else t[k].c=-1;}
void modify(int k,int x){t[k].c=t[k].d=x;if(x)t[k].num=mx;else t[k].num=0;}
void down(int k){
if(~t[k].d){
modify(k<<1,t[k].d);modify(k<<1|1,t[k].d);
t[k].d=-1;
}
}
void build(int k,int l,int r){
t[k].l=l;t[k].r=r;t[k].d=-1;t[k].c=0;t[k].num=0;
if(l==r)return;
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
int query(int k,int x){
if(t[k].l==t[k].r)return t[k].num;
down(k);
int mid=(t[k].l+t[k].r)>>1;
if(x<=mid)return query(k<<1,x);
else return query(k<<1|1,x);
}
void fix(int k,int x,int y){
if(t[k].l==t[k].r){t[k].num=y;t[k].c=-1;if(y==0)modify(k,0);if(y==mx)modify(k,1);return;}
down(k);
int mid=(t[k].l+t[k].r)>>1;
if(x<=mid)fix(k<<1,x,y);else fix(k<<1|1,x,y);
up(k);
}
void find_add(int k,int x){
if(t[k].c==1){modify(k,0);return;}
if(t[k].l==t[k].r){t[k].num++;if(t[k].num==mx)t[k].c=1;else t[k].c=-1;ok=1;return;}
down(k);
int mid=(t[k].l+t[k].r)>>1;
if(x>mid)find_add(k<<1|1,x);else{
find_add(k<<1,x);
if(!ok)find_add(k<<1|1,x);
}
up(k);
}
void find_del(int k,int x){
if(t[k].c==0){modify(k,1);return;}//
if(t[k].l==t[k].r){t[k].num--;if(t[k].num==0)t[k].c=0;else t[k].c=-1;ok=1;return;}//
down(k);
int mid=(t[k].l+t[k].r)>>1;
if(x>mid)find_del(k<<1|1,x);else{//
find_del(k<<1,x);
if(!ok)find_del(k<<1|1,x);
}
up(k);
}
void add(int x,int y){
int z=query(1,x);
fix(1,x,(z+y)%S);
ok=0;
if(z+y>mx)find_add(1,x+1);
}
void del(int x,int y){
int z=query(1,x);
fix(1,x,(z-y+S)%S);
ok=0;
if(z-y<0)find_del(1,x+1);
}
int main(){
n=read();t1=read();t2=read();t3=read();
build(1,1,N);
while(n--){
int kind=read();
if(kind==1){
int a=read(),b=read(),c=b/30;
if(a>0){
add(c+1,(a<<(b%30))&mx);
add(c+2,a>>(30-b%30));
}
else{
a=-a;
del(c+1,(a<<(b%30))&mx);
del(c+2,a>>(30-b%30));
}
}
else{
int x=read();
int y=query(1,x/30+1);
printf("%d\n",(y&(1<<(x%30)))?1:0);
}
}
return 0;
}
【NOI】2017 整数(BZOJ 4942,LOJ2302) 压位+线段树的更多相关文章
- 【bzoj4942】[Noi2017]整数 压位+线段树
题目描述 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 $x$ ,一开始为0. 接下来有 $n$ 个操作,每个操作都是以下两种类型中的一种: 1 a b :将 $x$ 加上整数 ...
- BZOJ 4942 NOI2017 整数 (压位+线段树)
题目大意:让你维护一个数x(x位数<=3*1e7),要支持加/减a*2^b,以及查询x的第i位在二进制下是0还是1 作为一道noi的题,非常考验写代码综合能力,敲+调+借鉴神犇的代码 3个多小时 ...
- LOJ 2302 「NOI2017」整数——压位线段树
题目:https://loj.ac/problem/2302 压30位,a最多落在两个位置上,拆成两次操作. 该位置加了 a 之后,如果要进位或者借位,查询一下连续一段 0 / 1 ,修改掉,再在含有 ...
- [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)
[BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并) 题面 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1 ...
- [BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...
- [NOI 2017]整数
Description 题库链接 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 \(x\) ,一开始为 \(0\) . 接下来有 \(n\) 个操作,每个操作都是以下两种类型中 ...
- 2017西安区域赛A / UVALive - 8512 线段树维护线性基合并
题意:给定\(a[1...n]\),\(Q\)次询问求\(A[L...R]\)的异或组合再或上\(K\)的最大值 本题是2017的西安区域赛A题,了解线性基之后你会发现这根本就是套路题.. 只要用线段 ...
- bzoj 1537: [POI2005]Aut- The Bus 线段树
bzoj 1537: [POI2005]Aut- The Bus 先把坐标离散化 设f[i][j]表示从(1,1)走到(i,j)的最优解 这样直接dp::: f[i][j] = max{f[i-1][ ...
- BZOJ 1012: [JSOI2008]最大数maxnumber 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1012 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能: ...
随机推荐
- (1) English Learning
1. no-brainer 不必花脑筋的事物 This tool is really no-brainer that almost everyone can use it. 这个工具太简单用了,不会 ...
- 评审other's意见
评审意见 1.组 a.界面不友好 b.没连数据库 2.组 a.没连数据库 b.无智能匹配当前时间 3.组 a.基本功能实现 b.界面未优化 4.组 ourselves 5.组 a.各反面较为完善 6. ...
- Daily Scrum - 11/16
时间:午饭 今天小组例会主要是汇报了各自的进度.任烁那边主要为工程添加了单词的类(包含各个参数等成员变量),方便以后实现算法:拜重阳实现了一个简易的“点进-点出”UI,可谓迈出了艰难的第一步:章玮和罗 ...
- Spark 实践——用 Scala 和 Spark 进行数据分析
本文基于<Spark 高级数据分析>第2章 用Scala和Spark进行数据分析. 完整代码见 https://github.com/libaoquan95/aasPractice/tre ...
- <转>HTML、CSS、font-family:中文字体的英文名称
宋体 SimSun 黑体 SimHei 微软雅黑 Microsoft YaHei 微软正黑体 Microsoft JhengHei 新宋体 NSimSun 新细明体 PMingLiU 细明体 Ming ...
- Pandas笔记目录
速查笔记 使用实例 Pandas-数据导入 (未完成) Pandas-数据探索 基础属性 shape indexs columns values dtype/dtypes 汇总和计算描述统计 coun ...
- html5 & upload files
html5 & upload files https://www.sitepoint.com/html5-ajax-file-upload/ https://www.webcodegeeks. ...
- 实现AJAX的基本步骤
实现AJAX的基本步骤 要完整实现一个AJAX异步调用和局部刷新,通常需要以下几个步骤: (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象. (2)创建一个新的HTTP请求,并指 ...
- 浅谈平衡树splay
首先splay和treap不一样,treap通过随机数来调整树的形态.但splay不一样,再每插入或操作一次后,你都会把他旋转到根,再旋转过程中树的形态会不断改变,这样来达到均摊效果 常数据大. 来看 ...
- 【UOJ#67】新年的毒瘤(Tarjan)
[UOJ#67]新年的毒瘤(Tarjan) 题面 UOJ 题解 一棵\(n\)个节点的树显然有\(n-1\)条边,在本题中意味着删去一个点之后还剩下\(n-2\)条边.那么找到所有度数为\(m-(n- ...