BZOJ4942 [Noi2017]整数
题解:
这题有点卡常数(自己的常数大)
每30位压成一个数
思路1:
每次操作拆成最多两个位置的操作
每加一次最多会进1
每减一次最多会退1
然后用线段树维护最近的非0位和非满位
然后就是区间赋值和单点修改
好难写没写出来QWQ
思路2:
分两个数组记录加操作(A)和减操作(B)
用set维护所有的不同位置
比较两个字符串的大小即找到第一个不同的位置
查询时分情况讨论
A的这一位是1还是0,B的这一位是1还是0,以及AB的后缀大小情况
讨论进位退位即可
暴力修改即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
const int u=30;
const int ux=(1<<u);
typedef long long Lint;
const int maxn=2000009;
int n;
int TT,t1,t2,t3;
Lint A[maxn]={0};
Lint B[maxn]={0};
set<int>S;
int cmp(int x){
set<int>::iterator it=S.upper_bound(x);
if(it==S.begin())return 0;
--it;
if(A[*it]>B[*it])return 1;
if(A[*it]<B[*it])return -1;
}
void pushup(int bol){
if(A[bol]==B[bol]){
if(S.count(bol))S.erase(bol);
}
if(A[bol]!=B[bol]){
if(!S.count(bol))S.insert(bol);
}
}
void print(Lint x){
if(x==0)return;
print(x>>1);
if(x&1)printf("1");
else printf("0");
}
int main(){
scanf("%d%d%d%d",&TT,&t1,&t2,&t3);
n=TT+1000;
while(TT--){
int opty,y;
Lint x;
scanf("%d",&opty);
if(opty==1){
scanf("%lld%d",&x,&y);
++y;
int bol=(y-1)/u+1;
y-=(bol-1)*u;
if(x>0){
A[bol]+=(x<<(y-1));
while(A[bol]>=ux){
A[bol+1]+=A[bol]/ux;
A[bol]%=ux;
pushup(bol);
++bol;
}
pushup(bol);
}else{
x=-x;
B[bol]+=(x<<(y-1));
while(B[bol]>=ux){
B[bol+1]+=B[bol]/ux;
B[bol]%=ux;
pushup(bol);
++bol;
}
pushup(bol);
}
}else{
scanf("%d",&y);
++y;
int bol=(y-1)/u+1;
y-=(bol-1)*u;
Lint tm1=A[bol]&((1<<(y-1))-1);
Lint tm2=B[bol]&((1<<(y-1))-1);
int tm3=cmp(bol-1);
int r=0;
if(tm1==tm2){
r=tm3;
}else if(tm1<tm2){
r=-1;
}else{
r=1;
}
if(A[bol]&(1<<(y-1))){
if(B[bol]&(1<<(y-1))){
if(r<0)printf("1\n");
else printf("0\n");
}else{
if(r>=0)printf("1\n");
else printf("0\n");
}
}else{
if(B[bol]&(1<<(y-1))){
if(r>=0)printf("1\n");
else printf("0\n");
}else{
if(r<0)printf("1\n");
else printf("0\n");
}
}
}
}
return 0;
}
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!

浙公网安备 33010602011771号