noi 2017 整数
(可怕的是noi2017 6道黑题 这觉对是神仙 瞄了一眼 可能就这个整数可以写。
这题是想让我们维护一个高精度的二进制数 且支持加法和减法以及第k位的查询。
对于第k位的查询我们显然是直接把这个数字变成二进制数 然后直接 查询输出答案。
至于加法和减法 观察 加上和减去这个数字 a*2^b 我们 把a进行二进制拆分 利用乘法分配律显然可以得到其实这个就是把这个a 在二进制的情况下左移b位。
每一位在x对应的二进制数下加减就好了。但是不难发现 有进位和退位这个东西的。
进位和退位显然是对一整个连续0 或者连续1 的区间作为修改。
当然 有部分分是 所有修改都在询问之后 这样的话我们单单只进行单点修改就好了,最后再统一进行处理。(这个很好处理的
这样的话 我们有一个比较显然的思路是 用线段树来维护这个过程 有了线段树的话 对于一段连续的修改 我们可以打上懒标记。
而查找到应该修改的区间的话连续的0 可以用 | 这个操作来搞 连续的1 可以用& 这个操作搞定来快速锁定所要修改的区间。
做到这里我们应该能得到了 13*4==72分的垃圾成绩而且还不好码。
因为考虑到这个数字有多大 a->30位数字 b->30n n<=1000000 那么这整个数字就是 9*10^8这么多的数位 全挂到线段树上早就爆了。
考虑压位操作 事实上我们是动态开点线段树 真实数位是 nlogn^2当然 这也足够大了也是9*10^8
考虑压位 我们直接30个二进制位为一个点 那么此时每次修改最多两个位置 n*2*logn ->240多MB 哇能过。
那么此时考虑查找第k位那就/30 在这个节点中找k%30这一位的数字!
修改呢 就是对应的位置直接相减,不够的话向前面借就好了,进位的话向前面进就好了。
当然 我们需要维护区间是否全为2^30-1 或 0 .
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double #define EPS 1e-8 #define s1(p) t[p].s1 #define s2(p) t[p].s2 #define tag(p) t[p].tag using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=1000010; int n,t1,t2,t3,root,num; ll d,mod,inf=(1<<30)-1; struct wy { int s1,s2; int tag; wy(){tag=-1;} }t[MAXN<<2]; inline void pushdown(int p) { s1(p<<1)=s2(p<<1)=tag(p); s1(p<<1|1)=s2(p<<1|1)=tag(p); tag(p<<1)=tag(p<<1|1)=tag(p); tag(p)=-1;return; } inline void pushup(int p) { s1(p)=s1(p<<1)&s1(p<<1|1); s2(p)=s2(p<<1)|s2(p<<1|1); return; } inline int ask(int p,int l,int r,int x) { if(l==r)return s1(p); int mid=(l+r)>>1; if(tag(p)!=-1)pushdown(p); pushup(p); if(x<=mid)return ask(p<<1,l,mid,x); return ask(p<<1|1,mid+1,r,x); } inline void change(int p,int l,int r,int x,int k) { if(l==r){s1(p)+=k;s2(p)+=k;return;} int mid=(l+r)>>1; if(tag(p)!=-1)pushdown(p); if(x<=mid)change(p<<1,l,mid,x,k); else change(p<<1|1,mid+1,r,x,k); pushup(p);return; } inline int calculate(int p,int l,int r,int x,int k) { if(k==inf){if(s1(p)==k)return 0;} else if(s2(p)==k)return 0; if(l==r)return l; int mid=(l+r)>>1; if(tag(p)!=-1)pushdown(p); pushup(p); if(x<=mid) { int ans=calculate(p<<1,l,mid,x,k); return ans?ans:calculate(p<<1|1,mid+1,r,x,k); } return calculate(p<<1|1,mid+1,r,x,k); } inline void modify(int p,int l,int r,int L,int R,int k) { if(L<=l&&R>=r) { s1(p)=s2(p)=tag(p)=k; return; } int mid=(l+r)>>1; if(tag(p)!=-1)pushdown(p); if(L<=mid)modify(p<<1,l,mid,L,R,k); if(R>mid)modify(p<<1|1,mid+1,r,L,R,k); pushup(p);return; } inline void add(int x,int y) { int sum=ask(1,1,num,x); //cout<<x<<' '<<y<<endl; if(sum+y<=inf)change(1,1,num,x,y); else { change(1,1,num,x,y-inf-1); int w=calculate(1,1,num,x+1,inf); if(w!=x+1)modify(1,1,num,x+1,w-1,0); change(1,1,num,w,1); } } inline void SBT(int x,int y) { int sum=ask(1,1,num,x); if(sum>=y)change(1,1,num,x,-y); else { change(1,1,num,x,inf+1-y); int w=calculate(1,1,num,x+1,0); if(w!=x+1)modify(1,1,num,x+1,w-1,inf); change(1,1,num,w,-1); } } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); n=read();t1=read();t2=read();t3=read(); num=n+2; for(int i=1;i<=n;++i) { ll p,a,b; p=read(); switch(p) { case 1: a=read();b=read(); d=b/30;mod=b%30; if(a>0) { add(d+1,(a<<mod)&inf); if(mod)add(d+2,((a<<mod)-((a<<mod)&inf))>>30); } else { a=-a; SBT(d+1,(a<<mod)&inf);//subtraction 减法 reduce 减少 if(mod)SBT(d+2,((a<<mod)-((a<<mod)&inf))>>30); } break; case 2: a=read()+1;d=a/30;mod=a%30; if(!mod) { int sum=ask(1,1,num,d); printf("%d\n",sum>>29); break; } int sum=ask(1,1,num,d+1); //cout<<sum<<endl; printf("%d\n",(sum>>(mod-1))&1); break; } } return 0; }