zoukankan      html  css  js  c++  java
  • 【NOI】2017 整数(BZOJ 4942,LOJ2302) 压位+线段树

    【题目】#2302. 「NOI2017」整数
    【题意】有一个整数x,一开始为0。n次操作,加上a*2^b,或询问2^k位是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
    ",(y&(1<<(x%30)))?1:0);
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    参考SQLHelper编写的OracleHelper
    微软原版SQLHelper类
    AppFabric 版本区分
    ASP.NET (HttpModule,HttpHandler)
    ASP.NET内部原理(HttpHandler和HttpModule)
    IIS 7.0, ASP.NET, pipelines, modules, handlers, and preconditions
    理解I/O Completion Port
    asp.net mvc跨域filter
    c#生成MD5字符串
    生成格式化的json
  • 原文地址:https://www.cnblogs.com/onioncyc/p/9086253.html
Copyright © 2011-2022 走看看