zoukankan      html  css  js  c++  java
  • 【洛谷3822】[NOI2017] 整数(压位+set)

    点此看题面

    大致题意: 给定一个整数(x)(初始为(0)),支持两种操作:给(x)加上(a imes 2^b);询问(x)二进制下第(k)位的值。

    压位

    遇到这种题应该自然而然就会想到压位吧。

    一开始我以为(a)只有正数(日常眼瞎),那么实际上每次只要暴力加、暴力进位就可以了。

    这种做法的复杂度我能口胡它是均摊(O(1))的,但由于我的证明方式比较难以描述,无法用书面文字表达,因此略了。

    然而,由于(a)可能存在负值,那么只要开局加一个(2^{3 imes 10^7}),然后重复执行(-1,+1,-1,+1,...),相当于每次都要跑满,直接升天。

    想了好久都没想出来该怎么修改这个做法,最终只好默默点开了题解。。。

    结果发现我的做法其实已经非常接近正解了。

    实际上,防止出现上述情况的最好方式,就是分别记录加上的数的总和减去的数的总和,那么复杂度依然有保证。

    接着考虑询问,我们先求出加与减的总和第(k)位的差值,然后只需判断(0sim k-1)位是否存在减法过程中出现借位即可。

    判断出现借位,一位一位枚举过去显然是不现实的。而一个较为优秀的方法,就是找到最高的不同位,比较两个总和中这一位的大小。

    那么如何找到最高的不同位呢?

    其实,我们可以开一个(set),然后只要把所有两个总和不同的一段压位值的编号扔入(set)中,每次使用(lower\_bound)即可找到最高的不同位。

    这道题就这样做完了。

    嗲吗

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define U unsigned int
    using namespace std;
    U a[N+5],b[N+5];set<int> S;
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define D isdigit(c=tc())
    		int f;char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0,f=1;W(!D) f=c^'-'?1:-1;W(x=(x<<3)+(x<<1)+(c&15),D);x*=f;}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    I void Add(U *s,U *k,Con U& x,CI y)
    {
    	#define F5(x) (s[x]^k[x]?(S.insert(x),0):S.count(x)&&(S.erase(x),0))
    	RI p=y>>5,q=y&31;U t=s[p];s[p]+=x<<q,F5(p);//先处理当前位
    	U w=((x>>1)>>(31-q))+(s[p++]<t);W(w) t=s[p],s[p]+=w,F5(p),w=s[p++]<t;//进位
    }
    I int Qry(CI x)
    {
    	RI p=x>>5,q=x&31,t=((a[p]^b[p])>>q)&1;//先求出第k位的差值
    	if((a[p]^b[p])&((1<<q)-1)) return t^((a[p]&((1<<q)-1))<(b[p]&((1<<q)-1)));//如果这一段压位值中已经存在不同
    	set<int>::iterator it=S.lower_bound(p);if(it==S.begin()) return t;//lower_bound找出最高的不同位
    	return --it,t^(a[*it]<b[*it]);//比较
    }
    int main()
    {
    	RI Qt,i,op,x,y;F.read(Qt,op,x,y);W(Qt--)
    		F.read(op,x),op==1?F.read(y),x>0&&(Add(a,b,x,y),0),x<0&&(Add(b,a,-x,y),0)//修改
    		:(putchar(48|Qry(x)),putchar('
    '));//询问
    	return 0;
    }
    
  • 相关阅读:
    Scala 中 for 循环 和 generator 的使用例子
    [转] tomcat进程意外退出的问题分析
    [转] Android:用GSON 五招之内搞定任何JSON数组
    [转] Scala 2.10.0 新特性之字符串插值
    [转] JQuery UI Tabs 动态添加页签,并跳转到新页签
    vim常用快捷键
    [转] 利用dockerize模板为容器内应用生成配置文件和环境变量
    [转] linux权限补充:rwt rwT rws rwS 特殊权限
    [转] #!/bin/sh & #!/bin/bash区别
    [转] 利用shell创建文本菜单与窗口部件的方法
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3822.html
Copyright © 2011-2022 走看看