【BZOJ4942】[NOI2017]整數(分塊)

【BZOJ4942】[NOI2017]整數(分塊)

題面

BZOJ
洛谷php

題解

暴力就是真正的暴力,直接手動模擬進位就行了。
此時複雜度是模擬的複雜度加上單次詢問的\(O(1)\)
因此咱們須要優化的是模擬的複雜度。
首先若是一位位單位加入,這個複雜度是均攤\(O(1)\)的。由於是均攤,因此咱們不能支持撤銷(即減法操做),因此加法減法必須分開處理。
對於位運算加法咱們考慮壓位(或者說分塊也是同樣的啦)
那麼加法就很容易處理了,只須要壓位以後找到對應的塊,而後直接暴力加上去就好了。
這裏稍微注意一下進位的細節。
減法相似處理。
那麼最後這樣子又變的很差查詢了。
而查詢的方法就是考慮這一位要不要退位。
退位的話就是加法的和減去減法的和,等價於比較兩個後綴大小,比較兩個後綴大小能夠用\(set\)維護哪些塊不相同,徹底相同的沒有必要比,只須要找到第一個不一樣的塊的就好了。
寫法上的話,看到洛谷題解裏用\(unsigned\ int\)\(32\)位,這樣子就不須要本身手動取模了,挺方便的。ios

#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
#define ui unsigned int
#define MAX 1000100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
ui A[MAX],B[MAX];
int n;
set<int> S;
int main()
{
    n=read();read();read();read();
    while(n--)
    {
        int opt=read();
        if(opt==1)
        {
            int a=read(),b=read();
            int p=b/32,r=b%32;
            if(a>0)
            {
                ui s0=(ui)a<<r,s1=r?((ui)a>>(32-r)):0;
                ui lst=A[p];A[p]+=s0;s1+=(lst>A[p]);
                if(A[p]^B[p])S.insert(p);
                else if(S.find(p)!=S.end())S.erase(p);
                ++p;
                while(s1)
                {
                    lst=A[p];A[p]+=s1;s1=(lst>A[p]);
                    if(A[p]^B[p])S.insert(p);
                    else if(S.find(p)!=S.end())S.erase(p);
                    ++p;
                }
            }
            else
            {
                a=-a;
                ui s0=(ui)a<<r,s1=r?((ui)a>>(32-r)):0;
                ui lst=B[p];B[p]+=s0;s1+=(lst>B[p]);
                if(A[p]^B[p])S.insert(p);
                else if(S.find(p)!=S.end())S.erase(p);
                ++p;
                while(s1)
                {
                    lst=B[p];B[p]+=s1;s1=(lst>B[p]);
                    if(A[p]^B[p])S.insert(p);
                    else if(S.find(p)!=S.end())S.erase(p);
                    ++p;
                }
            }
        }
        else
        {
            int a=read();
            int p=a/32,r=a%32;
            int ans=((A[p]>>r)&1)^((B[p]>>r)&1);
            ui va=A[p]&((1<<r)-1),vb=B[p]&((1<<r)-1);
            if(va<vb)ans^=1;
            else if(va>vb||S.empty()||p<=*S.begin());
            else
            {
                set<int>::iterator it=S.lower_bound(p);--it;
                if(A[*it]<B[*it])ans^=1;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
相關文章
相關標籤/搜索