NOI2017整数
Posted BLMontgomery
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOI2017整数相关的知识,希望对你有一定的参考价值。
发现进位或退位时,会有连续的一段1变成0或连续的0变成1,然后在后面产生一个进位或退位。于是我们只需要一颗线段树支持区间赋值,查询左边第一个1/0,以及单点查询值。可以把a按二进制拆开去修改,复杂度是O(nlognloga)的,这样好像过不去。
于是我的做法是在线段树的每个叶子节点存32位,用unsigned int保存,修改时就只需将a拆成跨过叶子节点的两部分分开进行修改即可,复杂度O(nlogn)。
查询左边第一个0/1时,可以维护每个区间是全为1/全为0/又有0又有1。
我的线段树好像十分丑,看看思想就行了吧。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<vector> #include<algorithm> #include<queue> #include<cmath> using namespace std; inline void read(int &re) { char ch=getchar();int g=1; while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘)g=-1;ch=getchar();} re=0; while(ch<=‘9‘&&ch>=‘0‘) re=(re<<1)+(re<<3)+ch-48,ch=getchar(); re*=g; } typedef long long ll; typedef double db; typedef unsigned int ui; const int inf=0x3f3f3f3f; const int N=2000050; const ui be[3]={0,(((1u<<31)-1u)<<1)+1u}; const ui bas=201351523u; int c,d,h,x,y,ss,in,ans=0,othc,jin,kep; ui a[(N<<2)+1]; int blo[N*30+1]; int tag[(N<<2)+1]; inline void pushdown(int o,int r,int l) { if(l!=r&&tag[o]) { tag[o<<1]=tag[o];tag[o<<1|1]=tag[o]; a[o<<1]=be[tag[o]&1];a[o<<1|1]=be[tag[o]&1]; } tag[o]=0; } inline void maintain(int o) { if(a[o<<1]==be[0]) a[o]=be[0]; else if(a[o<<1]==be[1]) a[o]=be[1]; else {a[o]=bas;return ;} if((a[o<<1|1]!=be[0]&&a[o<<1|1]!=be[1])||a[o<<1|1]!=a[o]) {a[o]=bas;return ;} } void update(int o,int r,int l,int k) { if(x<=l&&r<=y) { tag[o]=k; a[o]=be[k&1]; return ; } pushdown(o,r,l); int mid=l+r>>1; if(x<=mid) update(o<<1|1,mid,l,k); if(y>mid) update(o<<1,r,mid+1,k); maintain(o); } void always(int o,int r,int l,int k) { if(l==r) { for(int i=0;i<=31;++i) if(((a[o]>>i)&1u)==k) { a[o]^=(1<<i); for(int j=0;j<i;++j) a[o]^=(1<<j); break; } y=l-1; return ; } pushdown(o,r,l); int mid=l+r>>1; if(a[o<<1|1]!=be[!k]) always(o<<1|1,mid,l,k); else always(o<<1,r,mid+1,k); maintain(o); } void go(int o,int r,int l,int k) { if(!kep) return ; if(x<=l&&r<=y) { if(a[o]!=be[!k]) always(o,r,l,k),kep=0; return ; } pushdown(o,r,l); int mid=l+r>>1; if(x<=mid) go(o<<1|1,mid,l,k); if(y>mid) go(o<<1,r,mid+1,k); maintain(o); } void find(int o,int r,int l,int k) { if(blo[x]<=l&&r<=blo[y]) { if(!k) { ui rest=be[1]-a[o]; if(rest>=c) a[o]+=c; else jin=1,a[o]+=c; } else { if(a[o]>=c) a[o]-=c; else jin=1,a[o]-=c; } return ; } pushdown(o,r,l); int mid=l+r>>1; if(blo[x]<=mid) find(o<<1|1,mid,l,k); if(blo[y]>mid) find(o<<1,r,mid+1,k); maintain(o); } int query(int o,int r,int l,int k) { if(x<=l&&r<=y) return (a[o]>>(k%32))&1; pushdown(o,r,l); int mid=l+r>>1; if(x<=mid) return query(o<<1|1,mid,l,k); if(y>mid) return query(o<<1,r,mid+1,k); maintain(o); } int main() { int i,j,opt,T; read(T);read(i);read(i);read(i); h=log2(30.0*T)+0.999999999; int st=1<<h; for(i=0;i<st;++i) blo[i]=(i>>5)+1; h=log2(T)+0.999999999; while(T--) { read(opt); if(opt==1) { read(c);read(d); if(!c) continue; ui ago=c;int agod=d; jin=0;kep=1; if(c>0) { x=d;y=d; c<<=(d%32); if(c) find(1,1<<h,1,0);//tail if(jin) { x=blo[d]+1;y=1<<h; go(1,1<<h,1,0); x=blo[d]+1; if(x<=y) update(1,1<<h,1,2); } jin=0;kep=1; if(!(d%32)) continue; c=ago>>(32-d%32);d=d-d%32+32;//head x=d;y=d; if(c) find(1,1<<h,1,0); if(jin) { x=blo[d]+1;y=1<<h; go(1,1<<h,1,0); x=blo[d]+1; if(x<=y) update(1,1<<h,1,2); } } else { c=abs(c);ago=c; x=d;y=d; c<<=(d%32); if(c) find(1,1<<h,1,1); if(jin) { x=blo[d]+1;y=1<<h; go(1,1<<h,1,1); x=blo[d]+1; if(x<=y) update(1,1<<h,1,1); } jin=0;kep=1; if(!(d%32)) continue; c=ago>>(32-d%32);d=d-d%32+32; x=d;y=d; if(c) find(1,1<<h,1,1); if(jin) { x=blo[d]+1;y=1<<h; go(1,1<<h,1,1); x=blo[d]+1; if(x<=y) update(1,1<<h,1,1); } } } else { int k; read(k); x=blo[k];y=blo[k]; printf("%d\n",query(1,1<<h,1,k)); } } return 0; }
以上是关于NOI2017整数的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4942[Noi2017]整数 线段树+DFS(卡过)