【NOI2017】整数(压位分块+set)

【NOI2017】整数

题目简述:
一开始你有一个数 x = 0
n ( n 10 6 ) 次操作:
1.给 x 加上 a × 2 k ( a 10 9 , k 3 × 10 7 )
2.查询 x 的二进制表达表示 2 b ( b 3 × 10 7 ) 的那位的值
根据最基本的均摊分析,我们知道只支持加的二进制计数器均摊复杂度是 O ( 1 )
所以如果本题只支持加法的话可以利用 u n s i g n e d   i n t 压位
复杂度可以达到 O ( 30 n 32 ) = O ( n )
但是可能产生减法怎么办?
大力维护一个加法的结果
再维护一个减法的结果
查询怎么办?
大力比较后缀的大小即可
利用 s e t 记录大小不同的块的编号
所以这是道分块题2333
总复杂度 O ( 30 n 32 l o g 2 30 n 32 ) = O ( n l o g 2 n )
实际上根本跑不满,
还是很快的

#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));
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/assass_cannotin/article/details/80706183