【xsy1530】小Q與內存
阿新 • • 發佈:2018-09-13
常數 cor ret printf algorithm \n 暴力 時間復雜度 ora
一道很有意思的神題~
暴力平衡樹的復雜度很對(並不),但是$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 }
【xsy1530】小Q與內存