noi 2017 整数

  (可怕的是noi2017 6道黑题 这觉对是神仙 瞄了一眼 可能就这个整数可以写。

这题是想让我们维护一个高精度的二进制数 且支持加法和减法以及第k位的查询。

对于第k位的查询我们显然是直接把这个数字变成二进制数 然后直接 查询输出答案。

至于加法和减法 观察 加上和减去这个数字 a*2^b 我们 把a进行二进制拆分 利用乘法分配律显然可以得到其实这个就是把这个a 在二进制的情况下左移b位。

每一位在x对应的二进制数下加减就好了。但是不难发现 有进位和退位这个东西的。

进位和退位显然是对一整个连续0 或者连续1 的区间作为修改。

当然 有部分分是 所有修改都在询问之后 这样的话我们单单只进行单点修改就好了,最后再统一进行处理。(这个很好处理的

这样的话 我们有一个比较显然的思路是 用线段树来维护这个过程 有了线段树的话 对于一段连续的修改 我们可以打上懒标记。

而查找到应该修改的区间的话连续的0 可以用 | 这个操作来搞 连续的1 可以用& 这个操作搞定来快速锁定所要修改的区间。

做到这里我们应该能得到了 13*4==72分的垃圾成绩而且还不好码。

因为考虑到这个数字有多大 a->30位数字 b->30n n<=1000000 那么这整个数字就是 9*10^8这么多的数位 全挂到线段树上早就爆了。

考虑压位操作 事实上我们是动态开点线段树 真实数位是 nlogn^2当然 这也足够大了也是9*10^8 

考虑压位 我们直接30个二进制位为一个点 那么此时每次修改最多两个位置 n*2*logn ->240多MB 哇能过。

那么此时考虑查找第k位那就/30 在这个节点中找k%30这一位的数字!

修改呢 就是对应的位置直接相减,不够的话向前面借就好了,进位的话向前面进就好了。

当然 我们需要维护区间是否全为2^30-1 或 0 .

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define RI register ll
#define db double
#define EPS 1e-8
#define s1(p) t[p].s1
#define s2(p) t[p].s2
#define tag(p) t[p].tag
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=1000010;
int n,t1,t2,t3,root,num;
ll d,mod,inf=(1<<30)-1;
struct wy
{
    int s1,s2;
    int tag;
    wy(){tag=-1;}
}t[MAXN<<2];
inline void pushdown(int p)
{
    s1(p<<1)=s2(p<<1)=tag(p);
    s1(p<<1|1)=s2(p<<1|1)=tag(p);
    tag(p<<1)=tag(p<<1|1)=tag(p);
    tag(p)=-1;return;
}
inline void pushup(int p)
{
    s1(p)=s1(p<<1)&s1(p<<1|1);
    s2(p)=s2(p<<1)|s2(p<<1|1);
    return;
}
inline int ask(int p,int l,int r,int x)
{
    if(l==r)return s1(p);
    int mid=(l+r)>>1;
    if(tag(p)!=-1)pushdown(p);
    pushup(p);
    if(x<=mid)return ask(p<<1,l,mid,x);
    return ask(p<<1|1,mid+1,r,x);
}
inline void change(int p,int l,int r,int x,int k)
{
    if(l==r){s1(p)+=k;s2(p)+=k;return;}
    int mid=(l+r)>>1;
    if(tag(p)!=-1)pushdown(p);
    if(x<=mid)change(p<<1,l,mid,x,k);
    else change(p<<1|1,mid+1,r,x,k);
    pushup(p);return;
}
inline int calculate(int p,int l,int r,int x,int k)
{
    if(k==inf){if(s1(p)==k)return 0;}
    else if(s2(p)==k)return 0;
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(tag(p)!=-1)pushdown(p);
    pushup(p);
    if(x<=mid)
    {
        int ans=calculate(p<<1,l,mid,x,k);
        return ans?ans:calculate(p<<1|1,mid+1,r,x,k);
    }
    return calculate(p<<1|1,mid+1,r,x,k);
}
inline void modify(int p,int l,int r,int L,int R,int k)
{
    if(L<=l&&R>=r)
    {
        s1(p)=s2(p)=tag(p)=k;
        return;
    }
    int mid=(l+r)>>1;
    if(tag(p)!=-1)pushdown(p);
    if(L<=mid)modify(p<<1,l,mid,L,R,k);
    if(R>mid)modify(p<<1|1,mid+1,r,L,R,k);
    pushup(p);return;
}
inline void add(int x,int y)
{
    int sum=ask(1,1,num,x);
    //cout<<x<<' '<<y<<endl;
    if(sum+y<=inf)change(1,1,num,x,y);
    else
    {
        change(1,1,num,x,y-inf-1);
        int w=calculate(1,1,num,x+1,inf);
        if(w!=x+1)modify(1,1,num,x+1,w-1,0);
        change(1,1,num,w,1);
    }
}
inline void SBT(int x,int y)
{
    int sum=ask(1,1,num,x);
    if(sum>=y)change(1,1,num,x,-y);
    else
    {
        change(1,1,num,x,inf+1-y);
        int w=calculate(1,1,num,x+1,0);
        if(w!=x+1)modify(1,1,num,x+1,w-1,inf);
        change(1,1,num,w,-1);
    }
}
int main()
{
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    n=read();t1=read();t2=read();t3=read();
    num=n+2;
    for(int i=1;i<=n;++i)
    {
        ll p,a,b;
        p=read();
        switch(p)
        {
            case 1:
            a=read();b=read();
            d=b/30;mod=b%30;
            if(a>0)
            {
                add(d+1,(a<<mod)&inf);
                if(mod)add(d+2,((a<<mod)-((a<<mod)&inf))>>30);
            }
            else
            {
                a=-a;
                SBT(d+1,(a<<mod)&inf);//subtraction 减法 reduce 减少
                if(mod)SBT(d+2,((a<<mod)-((a<<mod)&inf))>>30);
            }
            break;
            case 2:
            a=read()+1;d=a/30;mod=a%30;
            if(!mod)
            {
                int sum=ask(1,1,num,d);
                printf("%d\n",sum>>29);
                break;
            }
            int sum=ask(1,1,num,d+1);
            //cout<<sum<<endl;
            printf("%d\n",(sum>>(mod-1))&1);
            break;
        }
    }
    return 0;
}
View Code

 

posted @ 2019-08-02 13:19  chdy  阅读(164)  评论(0编辑  收藏  举报