[2016北京集训测试赛5]小Q与内存-[线段树的神秘操作]

Description

 

Solution

哇真的异常服气。。线段树都可以搞合并和拆分的啊orzorz。神的世界我不懂

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int M=20000010;
const int N=200010;
int sz[M],lc[M],rc[M],tag[M],rt[N],all_work,cnt;
int _new(int x=1)
{
    int o=++cnt;
    tag[o]=x-1;
    sz[o]=1<<tag[o];
    lc[o]=rc[o]=0;
    return cnt;
}
void pushdown(int o)
{
    if (!tag[o]) return;
    lc[o]=_new(tag[o]);
    rc[o]=_new(tag[o]);
    tag[o]=0;
}
int split(int o,int k)
{
    int now=++cnt,re=now;
    pushdown(o);
    while (lc[o]||rc[o])
    {
        tag[now]=0;sz[now]=k;sz[o]-=k;
        if (k<=sz[lc[o]])
        {
            lc[now]=_new();rc[now]=0;
            now=lc[now];o=lc[o];
        } else
        {
            rc[now]=_new();lc[now]=lc[o];
            k-=sz[lc[o]];lc[o]=0;
            now=rc[now];o=rc[o];
        }
        pushdown(o);
    }
    tag[now]=tag[o]=0;
    sz[now]=k;sz[o]-=k;
    return re;
}
int merge(int x,int y)
{
    if (!x||!y) return x+y;
    lc[x]=merge(lc[x],lc[y]);
    rc[x]=merge(rc[x],rc[y]);
    sz[x]+=sz[y];
    return x;
}
int query(int x,int k)
{
    int o=rt[x];
    if (x>all_work||k>=sz[o]) return -1;
    int re=0;
    while (lc[o]||rc[o])
    {
        re<<=1;
        if (lc[o]&&k<sz[lc[o]]) o=lc[o];
        else k-=sz[lc[o]],re|=1,o=rc[o];
    }
    return re*(1<<tag[o])+k;
}
int T,n,root;
int _type,_k,_i,_p;
void clear()
{
    cnt=all_work=0;
    root=_new(31);
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        clear();
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&_type);
            if (_type==1)
            {
                scanf("%d",&_k);
                all_work++;
                rt[all_work]=0;
                if (sz[root]<_k) {printf("failed\n");continue;}
                rt[all_work]=split(root,_k);
                printf("ok\n");
            }
            if (_type==2)
            {
                scanf("%d",&_i);
                if (_i>all_work||!rt[_i]) {printf("failed\n");continue;}
                root=merge(root,rt[_i]);rt[_i]=0;
                printf("ok\n");
            }
            if (_type==3)
            {
                scanf("%d%d",&_i,&_p);
                int ans=query(_i,_p);
                if (ans!=-1) printf("%d\n",ans);
                else printf("failed\n");
            }
        }
    }
}

 

转载于:https://www.cnblogs.com/coco-night/p/9640928.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值