1. 程式人生 > >【xsy1530】小Q與內存

【xsy1530】小Q與內存

常數 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與內存