BZOJ 4942: [Noi2017]整数 ZKW线段树

title

\(~\)
BZOJ 4942
LUOGU 3822
题目搞简单一些:

有一个整数 \(x\),一开始为 \(0\)
接下来有 \(n\) 个操作,每个操作都是以下两种类型中的一种:
1 a b:将 \(x\) 加上整数 \(a\cdot 2^b\),其中 \(a\) 为一个整数, \(b\) 为一个非负整数
2 k :询问 \(x\) 在用二进制表示时,位权为 \(2^k\) 的位的值(即这一位上的 \(1\) 代表 \(2^k\)
保证在任何时候,\(x\geqslant 0\)
\(1\leqslant n\leqslant10^6,|a|\leqslant 10^9,0\leqslant b,k\leqslant 30n\)

analysis

考虑暴力,我们开两个数组来模拟进位(一个是 \(a>0\) ,另一个 \(a<0\) )。

对于询问,我们假设小于 \(k\) 位的部分 \(a>0\) 的是 \(s1\)\(a<0\) 的是 \(s2\)

讨论所有情况,我们可以得出结论:

  1. \(s1\geqslant s2\) ,输出答案为 \([x⊕y]\) ,其中 \(x\)\(a>0\) 的第 \(k\) 位的值, \(y\)\(a<0\) 的第 \(k\) 位的值。
  2. \(s1<s2\) ,输出答案为 \([x=y]\)
    这样总复杂度是 \(O(30nlog(30n))\) 的。

复杂度好像还不够优,考虑优化。
考虑什么呀,直接拿黑科技 \(zkw线段树\) 卡过去啦!

当然,这么牛逼的 \(zkw线段树\) 我也想不到,压位线段树又没精力学,要不是学习了 NaVi_Awson\(blog\) ,我就得写那接近 \(200+\)\(code\) 了。

对了,\(BZOJ\) 上不识别这个东西,害死我了。

putchar('0'+(s1[a]^s2[a]));

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6,maxm=maxn*30+300;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
    if (!x) *fe++=48;
    if (x<0) *fe++='-', x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) *fe++=ch[num--];
    *fe++='\n';
}

int s1[maxm],s2[maxm],t[(1<<26)+5],lst[32],bin[32],N;
inline void Change(int *s,int a,int b)
{
    int tot=0;
    for (int i=30; i>=0 && a; --i)
        if (bin[i]&a) lst[++tot]=i,a-=bin[i];
    int l=lst[tot]+b,r=lst[1]+b;
    for (int i=1; i<=tot; ++i)
    {
        int now=lst[i]+b;
        while (s[now]) s[now++]=0;
        r=max(r,now),s[now]=1;
    }
    for (int i=l; i<=r; ++i) t[i+N]=(s1[i]^s2[i]);
    for (l=(l+N)>>1,r=(r+N)>>1; l; l>>=1,r>>=1)
        for (int i=l; i<=r; ++i) t[i]=t[i<<1]|t[i<<1|1];
}

inline int query(int a)
{
    for (a+=N; a; a>>=1)
        if (a&1&t[a^1])
        {
            for (a^=1; a<N; a=a<<1|t[a<<1|1]);
            return a-N;
        }
    return -1;
}

int main()
{
    int n,t1;read(n);read(t1),read(t1),read(t1);
    for (N=1; N<=n*30; N<<=1);
    bin[0]=1;
    for (int i=1; i<=30; ++i) bin[i]=(bin[i-1]<<1);
    while (n--)
    {
        int opt,a,b;read(opt);
        if (opt==1)
        {
            read(a);read(b);
            if (a<0) Change(s2,-a,b);
            else Change(s1,a,b);
        }
        else
        {
            read(a);int now=query(a);
            if (now==-1 || s1[now]>s2[now]) write((int)(s1[a]^s2[a]));
            else write((int)(s1[a]==s2[a]));
        }
    }
    flush();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/G-hsm/p/11318072.html