bzoj4742 NOI2017整数
Posted nicodafagood
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4742 NOI2017整数相关的知识,希望对你有一定的参考价值。
不会考试题来补一手题解
题目背景
在人类智慧的山巅,有着一台字长为10485761048576 位(此数字与解题无关)的超级计算机,著名理论计算机科
学家P博士正用它进行各种研究。不幸的是,这天台风切断了电力系统,超级计算机
无法工作,而 P 博士明天就要交实验结果了,只好求助于学过OI的你. . . . . .
题目描述
P 博士将他的计算任务抽象为对一个整数的操作。
具体来说,有一个整数xx ,一开始为00 。
接下来有nn 个操作,每个操作都是以下两种类型中的一种:
-
1 a b
:将xx 加上整数a\cdot 2^ba?2b ,其中aa 为一个整数,bb 为一个非负整数 -
2 k
:询问xx 在用二进制表示时,位权为2^k2k 的位的值(即这一位上的11 代表 2^k2k )
保证在任何时候,x\geqslant 0x?0 。
输入输出格式
输入格式:
输入的第一行包含四个正整数n,t_1,t_2,t_3n,t1?,t2?,t3? ,nn 的含义见题目描述,t_1t1? ,t_2t2? ,t_3t3? 的具体含义见子任务。
接下来nn 行,每行给出一个操作,具体格式和含义见题目描述。
同一行输入的相邻两个元素之间,用恰好一个空格隔开。
输出格式:
对于每个询问操作,输出一行,表示该询问的答案(00 或11 )。对于加法操作,没有任何输出。
说明
n<=1e6
a<=1e9
b<= 30*n
考虑一般做法
建一颗大小为30*n的线段树
将a的每一位拆开,然后在线段树里找下一个1或0
复杂度O(30n*log30n)
看起来很慢
其实常数够优秀的话是可以A的
对于非wys选手来说
其实不需要一位一位的计算
一个叶子节点记录30位
将a拆成2个数
因为进位退位最多为1
在线段树上面找出一个点以后最长连续一段的0或者(1<<30)-1
然后就做完了
复杂度O(nlogn)
代码不长,挺好写的,就300行左右,也就是一个上午的时间就可以对着大数据调出来啦
//%std #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<stack> #include<set> #include<map> using namespace std; #define lovelive long long #define lc son[x][0] #define rc son[x][1] #define lowbit(x) (x&(-x)) #define pt vc const int N=1e6+100; void read(int &x) { int p=1; x=0; char c=getchar(); while(c<‘0‘||c>‘9‘) { if(c==‘-‘) p=-1; c=getchar(); } while(c>=‘0‘&&c<=‘9‘) { x=x*10+c-48; c=getchar(); } x*=p; } struct tree{ int l,r; bool sum1,sum0; int lazy,key; }t[N*4]; void buildtree(int i,int l,int r) { t[i].l=l; t[i].r=r; t[i].lazy=-1; t[i].sum0=1; if(l==r) return; int mid=(l+r)>>1; buildtree(i<<1,l,mid); buildtree(i<<1|1,mid+1,r); } void pushdown(int i) { if(t[i].lazy==-1) return; t[i<<1].sum0=t[i<<1|1].sum0=t[i].lazy^1; t[i<<1].sum1=t[i<<1|1].sum1=t[i].lazy; t[i<<1].lazy=t[i<<1|1].lazy=t[i].lazy; if(t[i<<1].l==t[i<<1].r) t[i<<1].key=t[i].lazy? (1<<30)-1:0; if(t[i<<1|1].l==t[i<<1|1].r) t[i<<1|1].key=t[i].lazy? (1<<30)-1:0; t[i].lazy=-1; } void change(int i,int pos,int x) { if(t[i].l>pos||t[i].r<pos) return; if(t[i].l==t[i].r) { t[i].sum0=t[i].sum1=0; t[i].key=x; if(x==((1<<30)-1)) t[i].sum1=1; else if(!x) t[i].sum0=1; return; } pushdown(i); change(i<<1,pos,x); change(i<<1|1,pos,x); t[i].sum1=t[i<<1].sum1&t[i<<1|1].sum1; t[i].sum0=t[i<<1].sum0&t[i<<1|1].sum0; } void change_(int i,int l,int r,int x) { if(l>t[i].r||r<t[i].l) return; if(l<=t[i].l&&t[i].r<=r) { t[i].sum1=x; t[i].sum0=x^1; t[i].lazy=x; if(t[i].l==t[i].r) t[i].key=x? (1<<30)-1:0; return; } pushdown(i); change_(i<<1,l,r,x); change_(i<<1|1,l,r,x); t[i].sum1=t[i<<1].sum1&t[i<<1|1].sum1; t[i].sum0=t[i<<1].sum0&t[i<<1|1].sum0; } int find_key(int pos) { int i=1; while(1) { if(t[i].l==t[i].r) return t[i].key; pushdown(i); if(pos<=t[i<<1].r) i=i<<1; else i=i<<1|1; } } int find_num1(int pos) { int i=1,r=1,pre; while(t[i].l!=t[i].r) { pushdown(i); if(pos<=t[i<<1].r) i=i<<1; else i=i<<1|1; } if(!t[i].sum1) return 0; pre=i; i>>=1; while(i!=1) { if(!(pre&1)) { if(!t[pre^1].sum1) break; else r+=t[pre^1].r-t[pre^1].l+1; } pre=i; i>>=1; } if(pre==(i<<1|1)) return r; i=i<<1|1; while(1) { if(t[i].l==t[i].r) { r+=t[i].sum1; break; } pushdown(i); if(t[i<<1].sum1) r+=t[i<<1].r-t[i<<1].l+1,i=i<<1|1; else i=i<<1; } return r; } int find_num0(int pos) { int i=1,r=1,pre; while(t[i].l!=t[i].r) { pushdown(i); if(pos<=t[i<<1].r) i=i<<1; else i=i<<1|1; } if(!t[i].sum0) return 0; pre=i; i>>=1; while(i!=1) { if(!(pre&1)) { if(!t[pre^1].sum0) break; else r+=t[pre^1].r-t[pre^1].l+1; } pre=i; i>>=1; } if(pre==(i<<1|1)) return r; i=i<<1|1; while(1) { if(t[i].l==t[i].r) { r+=t[i].sum0; break; } pushdown(i); if(t[i<<1].sum0) r+=t[i<<1].r-t[i<<1].l+1,i=i<<1|1; else i=i<<1; } return r; } void add(int pos,int a) { int tmp=find_key(pos); if(tmp+a<(1<<30)) change(1,pos,tmp+a); else { change(1,pos,tmp+a-(1<<30)); tmp=find_num1(pos+1); if(tmp) change_(1,pos+1,pos+tmp,0); change(1,pos+tmp+1,find_key(pos+tmp+1)+1); } } void del(int pos,int a) { int tmp=find_key(pos); if(tmp>=a) change(1,pos,tmp-a); else { change(1,pos,tmp-a+(1<<30)); tmp=find_num0(pos+1); if(tmp) change_(1,pos+1,pos+tmp,1); change(1,pos+tmp+1,find_key(pos+tmp+1)-1); } } int main() { int n,fk,opt,a,b,x,y,tmp,a1,a2; // freopen("test.in","r",stdin); // freopen("test.out","w",stdout); read(n);read(fk);read(fk);read(fk); buildtree(1,1,n+1); for(int i=1;i<=n;i++) { if(i==4501) i--,i++; read(opt); if(opt&1) { read(a);read(b); x=b/30+1; y=b%30; if(a<0) { a=-a; a1=(a<<y)&((1<<30)-1); a2=a>>(30-y); del(x,a1); if(a2) del(x+1,a2); } else { a1=(a<<y)&((1<<30)-1); a2=a>>(30-y); add(x,a1); if(a2) add(x+1,a2); } } else { read(a); x=a/30+1; y=a%30; tmp=find_key(x); cout<<(tmp>>y&1)<<"\n"; } } return 0; } /* 10000 1 1 1 1 1 30000 1 1 100 1 -1 1000 1 1 10000 2 10000 10000 1 1 1 1 1 30000 1 -1 1000 1 1 10000 2 10000 */
以上是关于bzoj4742 NOI2017整数的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4942 & UOJ314:[NOI2017]整数——题解