(2016北京集训十)【xsy1530】小Q与内存

一道很有意思的神题~

暴力平衡树的复杂度很对(并不),但是$2^{30}$的空间一脸屎

这题的正解是一个类似线段树的数据结构,我觉得很有创新性Orz

首先可以想到一种暴力就是用一个点代表一个区间,然后用链表维护这些点的集合,每次alloc操作就相当于割开未分配的区间,即增加了一个点,free操作就相当于合并。所以最多会产生$n$个点,单次操作$O(n)$,时间复杂度$O(n^2)$但是不满,貌似常数小就可以拿60;

把这个集合看成一个序列的话,快速修改点的信息肯定会想到线段树,正解就是用线段树去维护这个“区间集合”;

但是直接暴力线段树的话并不比平衡树优,需要用类似区间修改打懒标记的方法:如果一个点没被分割过,那就先打上标记,不实际创建它的儿子,到访问时才真正建出来,这样就能达到每次操作均摊$O(logn)$的复杂度。

开始算了算$2^{30}$线段树需要一千多万个节点,觉得很虚,结果一看空间1G瞬间不虚。。。

其实我一直很喜欢这种二叉结构,觉得很优美,写起来也很舒服。。。

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7 #define inf 2147483647
  8 #define eps 1e-9
  9 #define DCSB {puts("failed");continue;}
 10 using namespace std;
 11 typedef long long ll;
 12 struct node{
 13     int lc,rc,v,bit;
 14 }t[20000001];
 15 int T,n,op,p,q,rt,cnt,tot,rts[200001];
 16 void pd(int u){
 17     if(t[u].bit==-1)return;
 18     if(t[u].bit>0){
 19         t[u].lc=++cnt;
 20         t[u].rc=++cnt;
 21         t[t[u].lc].bit=t[t[u].rc].bit=t[u].bit-1;
 22         t[t[u].lc].v=t[t[u].rc].v=1<<(t[u].bit-1);
 23     }else t[u].lc=t[u].rc=-1;
 24     t[u].bit=-1;
 25 }
 26 int ins(int u,int p){
 27     int now=++cnt,ret=now;
 28     pd(u);
 29     while(t[u].lc!=-1){
 30         t[now].bit=-1;
 31         t[u].v-=p;
 32         t[now].v=p;
 33         if(p<t[t[u].lc].v){
 34             t[now].rc=0;
 35             now=t[now].lc=++cnt;
 36             u=t[u].lc;
 37         }else{
 38             p-=t[t[u].lc].v;
 39             t[now].lc=t[u].lc;
 40             t[now].rc=++cnt;
 41             t[u].lc=0;
 42             now=t[now].rc;
 43             u=t[u].rc;
 44         }
 45         pd(u);
 46     }
 47     t[u].v-=p;
 48     t[now].bit=-1;
 49     t[now].v=p;
 50     t[now].lc=-1;
 51     return ret;
 52 }
 53 int del(int u,int v){
 54     if(!u||!v)return u|v;
 55     if(t[u].lc!=-1){
 56         t[u].lc=del(t[u].lc,t[v].lc);
 57         t[u].rc=del(t[u].rc,t[v].rc);
 58     }
 59     t[u].v+=t[v].v;
 60     return u;
 61 }
 62 int calc(int u,int p){
 63     int ret=0;
 64     while(t[u].bit==-1&&t[u].lc!=-1){
 65         ret*=2;
 66         if(t[u].lc&&p<t[t[u].lc].v)u=t[u].lc;
 67         else{
 68             p-=t[t[u].lc].v;
 69             u=t[u].rc;
 70             ret++;
 71         }
 72     }
 73     if(t[u].bit==-1)return ret;
 74     else return ret*(1<<t[u].bit)+p;
 75 }
 76 int main(){
 77     scanf("%d",&T);
 78     while(T--){
 79         rt=cnt=1;
 80         t[1].bit=30;
 81         t[1].v=1<<30;
 82         tot=0;
 83         scanf("%d",&n);
 84         for(int i=1;i<=n;i++){
 85             scanf("%d",&op);
 86             if(op==1){
 87                 scanf("%d",&p);
 88                 rts[++tot]=0;
 89                 if(t[rt].v<p)DCSB
 90                 rts[tot]=ins(rt,p);
 91                 puts("ok");
 92             }
 93             if(op==2){
 94                 scanf("%d",&p);
 95                 if(p>tot||!rts[p])DCSB
 96                 rt=del(rt,rts[p]);
 97                 rts[p]=0;
 98                 puts("ok");
 99             }
100             if(op==3){
101                 scanf("%d%d",&p,&q);
102                 if(p>tot||!rts[p]||q>=t[rts[p]].v)DCSB
103                 printf("%d\n",calc(rts[p],q));
104             }
105         }
106     }
107     return 0;
108 }

 

posted @ 2018-09-13 11:51  DCDCBigBig  阅读(139)  评论(0编辑  收藏  举报