标签:scan clu 空间 直接 void i++ type 就是 style
一道很有意思的神题~
暴力平衡树的复杂度很对(并不),但是$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 }
标签:scan clu 空间 直接 void i++ type 就是 style
原文地址:https://www.cnblogs.com/dcdcbigbig/p/9639709.html