BZOJ4942 NOI2017整数(线段树)

  首先把每32位压成一个unsigned int(当然只要压起来能过就行)。如果不考虑进/退位的话,每次只要将加/减上去的数拆成两部分直接单点修改就好了。那么考虑如何维护进/退位。可以发现进位的过程其实就是将一段连续的inf改为0,并把之后一位+1,也就是说只要找到某一位之后第一个不是inf的位就好了。我们用线段树维护这个东西,记录一下某个节点表示的区间是否全为inf。查询时先从叶子节点往上爬,直到当前节点代表的区间中在该叶子节点右边的位不全为inf时停止,之后再往下找最左的非inf位。退位类似。这样的话复杂度就是O(nlogn)。

  写起来挺烦的,注意一下各种细节,码力极弱选手表示调了快一天……惨惨。

// luogu-judger-enable-o2
#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 1000010
#define ui unsigned int
#define inf 4294967295
#define lson (k<<1)
#define rson (k<<1|1)
#define getmid; int mid=tree[k].l+tree[k].r>>1;
int n;
struct data{int l,r,tag,size,sumzero,suminf;ui num;
}tree[N<<2];
bool isleaf(int k){return tree[k].size==1;}
void build(int k,int l,int r)
{
    tree[k].l=l,tree[k].r=r,tree[k].size=r-l+1;
    tree[k].sumzero=tree[k].size,tree[k].suminf=0;
    if (isleaf(k)) return;
    getmid;
    build(lson,l,mid);
    build(rson,mid+1,r);
}
void up(int k)
{
    tree[k].sumzero=tree[lson].sumzero+tree[rson].sumzero;
    tree[k].suminf=tree[lson].suminf+tree[rson].suminf;
}
void update(int k,int tag)
{
    if (tag>0) tree[k].sumzero=tree[k].size,tree[k].suminf=0;
    else tree[k].sumzero=0,tree[k].suminf=tree[k].size;
    tree[k].tag=tag;
    if (isleaf(k)) tree[k].num=tag>0?0:inf;
}
void down(int k)
{
    if (tree[k].tag)
    {
        update(lson,tree[k].tag);
        update(rson,tree[k].tag);
        tree[k].tag=0;
    }
}
int find(int k,int x)
{
    if (isleaf(k)) return k;
    down(k);
    getmid;
    int ans;
    if (x<=mid) ans=find(lson,x);
    else ans=find(rson,x);
    up(k);
    return ans;
}
void modify(int k,int l,int r,int tag)
{
    if (tree[k].l==l&&tree[k].r==r)
    {
        update(k,tag);
        return;
    }
    down(k);
    getmid;
    if (r<=mid) modify(lson,l,r,tag);
    else if (l>mid) modify(rson,l,r,tag);
    else modify(lson,l,mid,tag),modify(rson,mid+1,r,tag);
    up(k);
}
int add(int k,int p,ui x)
{
    if (isleaf(k))
    {
        int v=inf-tree[k].num<x;
        tree[k].num+=x;
        tree[k].sumzero=(tree[k].num==0);
        tree[k].suminf=(tree[k].num==inf);
        return v;
    } 
    down(k);
    getmid;
    int ans;
    if (p<=mid) ans=add(lson,p,x);
    else ans=add(rson,p,x);
    up(k);
    return ans;
}
int dec(int k,int p,ui x)
{
    if (isleaf(k))
    {
        int v=tree[k].num<x;
        tree[k].num-=x;
        tree[k].sumzero=(tree[k].num==0);
        tree[k].suminf=(tree[k].num==inf);
        return v;
    }
    down(k);
    getmid;
    int ans;
    if (p<=mid) ans=dec(lson,p,x);
    else ans=dec(rson,p,x);
    up(k);
    return ans;
}
void pushup(int k)
{
    if (tree[k].suminf)
    {
        int t=k,cnt=0;
        while (tree[k].suminf-cnt==tree[k].r-tree[t].l+1) 
        {
            if (k&1) cnt+=tree[k-1].suminf;
            k>>=1;
        }
        k=rson;
        while (!isleaf(k))
        {
            down(k);
            if (tree[lson].suminf==tree[lson].size) k=rson;
            else k=lson;
        }
        modify(1,tree[t].l,tree[k].l-1,1);
    }
    add(1,tree[k].l,1);
}
void pushdown(int k)
{
    if (tree[k].sumzero)
    {
        int t=k,cnt=0;
        while (tree[k].sumzero-cnt==tree[k].r-tree[t].l+1) 
        {
            if (k&1) cnt+=tree[k-1].sumzero;
            k>>=1;
        }
        k=rson;
        while (!isleaf(k))
        {
            down(k);
            if (tree[lson].sumzero==tree[lson].size) k=rson;
            else k=lson;
        }
        modify(1,tree[t].l,tree[k].l-1,-1);
    }
    dec(1,tree[k].l,1);
}
int query(int k,int p,int x)
{
    if (isleaf(k)) return tree[k].num>>x&1;
    down(k);
    getmid;
    int ans;
    if (p<=mid) ans=query(lson,p,x);
    else ans=query(rson,p,x);
    up(k);
    return ans;
}
int main()
{
    n=read();read(),read(),read();
    build(1,1,n+2);
    for (int i=1;i<=n;i++)
    {
        int op=read();
        if (op==1)
        {
            int x=read(),y=read();
            if (x>0)
            {
                ui v=x;
                ui a=v<<(y&31),b=(y&31)?(v>>(32-(y&31))):0;
                if (a>0) b+=add(1,(y>>5)+1,a);
                if (b>0)
                {
                    a=add(1,(y>>5)+2,b);
                    if (a>0) pushup(find(1,(y>>5)+3));
                }
            }
            else
            {
                ui v=abs(x);
                ui a=v<<(y&31),b=(y&31)?(v>>(32-(y&31))):0;
                if (a>0) b+=dec(1,(y>>5)+1,a);
                if (b>0)
                {
                    a=dec(1,(y>>5)+2,b);
                    if (a>0) pushdown(find(1,(y>>5)+3));
                }
            }
        }
        else
        {
            int x=read();
            printf("%d\n",query(1,(x>>5)+1,x&31));
        }
    }
    return 0;
}

 

posted @ 2018-08-01 13:31  Gloid  阅读(123)  评论(0编辑  收藏  举报