【NOI2017】整数
题目简述:
一开始你有一个数
次操作:
1.给
加上
2.查询
的二进制表达表示
的那位的值
根据最基本的均摊分析,我们知道只支持加的二进制计数器均摊复杂度是
的
所以如果本题只支持加法的话可以利用
压位
复杂度可以达到
但是可能产生减法怎么办?
大力维护一个加法的结果
再维护一个减法的结果
查询怎么办?
大力比较后缀的大小即可
利用
记录大小不同的块的编号
所以这是道分块题2333
总复杂度
实际上根本跑不满,
还是很快的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int MAXN=1000010;
typedef unsigned long long lsq;
lsq Plus[MAXN],Minus[MAXN];
set<int>st;
set<int>::iterator it;
int n,t1,t2,t3,opt;
int main()
{
scanf("%d%d%d%d",&n,&t1,&t2,&t3);
while(n--)
{
scanf("%d",&opt);
if(opt==1)
{
int a,b;
scanf("%d%d",&a,&b);
int pos1=b/64,pos2=b%64;
if(a>0)
{
lsq temp=Plus[pos1];
Plus[pos1]+=(lsq)(a<<pos2);
lsq up=(lsq)(a>>(31-pos2));
up>>=31;
up>>=2;
up+=(Plus[pos1]<temp);
if(Plus[pos1]^Minus[pos1])
st.insert(pos1);
else if(st.count(pos1))st.erase(pos1);
++pos1;
while(up)
{
temp=Plus[pos1];
Plus[pos1]+=up;
up=(Plus[pos1]<temp);
if(Plus[pos1]^Minus[pos1])
st.insert(pos1);
else if(st.count(pos1))st.erase(pos1);
++pos1;
}
}
else if(a<0)
{
a=-a;
lsq temp=Minus[pos1];
Minus[pos1]+=(lsq)(a<<pos2);
lsq up=(lsq)(a>>(31-pos2));
up>>=31;
up>>=2;
up+=(Minus[pos1]<temp);
if(Plus[pos1]^Minus[pos1])
st.insert(pos1);
else if(st.count(pos1))st.erase(pos1);
++pos1;
while(up)
{
temp=Minus[pos1];
Minus[pos1]+=up;
up=(Minus[pos1]<temp);
if(Plus[pos1]^Minus[pos1])
st.insert(pos1);
else if(st.count(pos1))st.erase(pos1);
++pos1;
}
}
}
else
{
int b;
scanf("%d",&b);
int pos1=b/64,pos2=b%64;
int ans=(lsq)((Plus[pos1]>>pos2)^(Minus[pos1]>>pos2))&1;
lsq valp=(lsq)Plus[pos1]%(1<<pos2),valm=(lsq)Minus[pos1]%(1<<pos2);
if(valp<valm)printf("%d\n",(ans^1));
else if(valp>valm||(!st.size())||pos1<=*(st.begin()))
printf("%d\n",ans);
else
{
it=st.lower_bound(pos1);
--it;
if(Plus[*it]>Minus[*it])printf("%d\n",ans);
else printf("%d\n",(ans^1));
}
}
}
}