【搞基資料結構】【樹套樹】ZOJ2112 Dynamic Rankings kth_number

來源:互聯網
上載者:User

動態查詢區間第k小,包括兩個操作Q x y k和C i j,查詢區間x y的第k小和把第i個數安替換成j。


靜態區間k小可以用劃分樹或者歸併樹,動態就只能樹套樹或者樹狀數組套主席樹,樹狀數組套主席樹暫時還沒有寫出來,這裡講一下樹套樹的兩種寫法。

首先考慮到線段樹可以用於區間查詢,而平衡樹可以查詢某個數位名次【小於或者小於等於這個數位個數】,這樣考慮到用線段樹套平衡樹的方式實現查詢某個數字在區間x y上的名次,於是得到建樹方式是:按區間建立線段樹,線段樹的每一個結點建立一棵平衡樹,因為無法直接查詢第k小,那麼只能採用二分答案的方式,查詢數字區間x y上的名次,這樣查詢的總複雜度是二分答案一個logn,線段樹上一個logn,平衡樹上一個logn,總的複雜度就是log^3n;更新就是線段樹的單點更新方式,對於結點每個平衡樹先把原來的值刪掉,再把新的值加上去,總複雜度是log^2n。空間複雜度,線段樹一共logn層,每層n個結點,所以總的空間是nlogn。

還有另一種樹套樹的方式可以把查詢的複雜度變成log^2n,不過要先離線讀入然後離散化。

這裡首先考慮如何用線段樹查詢整個數列的第k大,首先將數列離散化然後按範圍建立一棵線段樹,將每個點插入並維護區間裡插入的數字個數,每次查詢的時候先看左子樹有沒有k個數,如果有就查詢左子樹的第k小,否則去右子樹查詢第k-左子樹,當線段樹上的區間l==r時返回l就是離散化以後的答案。

區間查詢的話,就是每個節點建一個下標平衡樹,查詢左子樹有多少>=x && <=y的個數,超過k就在左子樹查詢,否則去右子樹查詢。

這種建樹方式需要離線讀入,如果要強制線上的話可以將範圍建成一棵線段樹,然後每次更新時不更新到底,而是打標記,需要查詢時再向下建樹,不過這種方法我沒有實現過,因為不知道怎麼打標記。

下面兩個是兩種不同建樹方式的提交情況,0168是按下標建樹,2535是按值建樹。

我是採用線段樹套treap,因為treap比較好寫。

按下標建樹:

int id(int l,int r){ return l+r | l!=r; }int tree[N<<1];struct treap{ int key,wht,count,sz,ch[2]; }tp[N*20];int nodecount;void init(){ tp[0].sz=0; tp[0].wht=-INF; tp[0].key=-1; nodecount=0; }void update(int x){ tp[x].sz=tp[tp[x].ch[0]].sz+tp[x].count+tp[tp[x].ch[1]].sz; }void rotate(int &x,int t){ int y=tp[x].ch[t]; tp[x].ch[t]=tp[y].ch[!t]; tp[y].ch[!t]=x;  update(x); update(y); x=y;}void insert(int &x,int t){   if(! x)    { x=++nodecount; tp[x].key=t; tp[x].wht=rand(); tp[x].count=1;      tp[x].ch[0]=tp[x].ch[1]=0;    }else if(tp[x].key==t) tp[x].count++;    else    { int k=tp[x].key<t; insert(tp[x].ch[k],t);      if(tp[x].wht<tp[tp[x].ch[k]].wht) rotate(x,k);    }    update(x);}void erase(int &x,int t){   if(tp[x].key==t)    {   if(tp[x].count==1)        { if(! tp[x].ch[0] && ! tp[x].ch[1]){ x=0; return; }          rotate(x,tp[tp[x].ch[0]].wht<tp[tp[x].ch[1]].wht); erase(x,t);        }else tp[x].count--;    }else erase(tp[x].ch[tp[x].key<t],t);    update(x);}int select(int x,int k){   if(! x) return 0;    if(k<tp[x].key) return select(tp[x].ch[0],k);    int q=0,p=tp[tp[x].ch[0]].sz+tp[x].count;    if(k>tp[x].key) q=select(tp[x].ch[1],k);    return p+q;}int a[N],n,m,ans;void treeinsert(int l,int r,int i,int x){   insert(tree[id(l,r)],x); if(l==r) return; int m=(l+r)>>1;    if(i<=m) treeinsert(l,m,i,x); if(i>m) treeinsert(m+1,r,i,x);}void del(int l,int r,int i,int x){   erase(tree[id(l,r)],x); if(l==r) return; int m=(l+r)>>1;    if(i<=m) del(l,m,i,x); if(i>m) del(m+1,r,i,x);}void query(int l,int r,int L,int R,int x){   if(L<=l && R>=r){ ans+=select(tree[id(l,r)],x); return; }    int m=(l+r)>>1; if(L<=m) query(l,m,L,R,x); if(R>m) query(m+1,r,L,R,x);}int main(){   int tt; scanf("%d",&tt);    while (tt--)    { scanf("%d%d",&n,&m); init(); memset(tree,0,sizeof(tree));      for(int i=1;i<=n;i++){ scanf("%d",&a[i]); treeinsert(1,n,i,a[i]); }      while (m--)      { char s[5]; int x,y,c; scanf("%s",s);        if(s[0]=='C')        { scanf("%d %d",&x,&y); del(1,n,x,a[x]); a[x]=y;          treeinsert(1,n,x,a[x]);        }else        { scanf("%d %d %d",&x,&y,&c); int l=0,r=INF,mid;          while (l<r)          { ans=0; mid=(l+r)>>1; query(1,n,x,y,mid);            if(ans<c) l=mid+1; else r=mid;          }          printf("%d\n",l);        }       }    }    return 0;}

按值建樹:

#define N 60010#define M 10010struct treap{    int key,wht,count,sz,ch[2];}tp[N*15];int tree[N<<1];int nodecount,root;void init(){ tp[0].sz=0; tp[0].wht=-INF; nodecount=0; root=0;}void update(int x){tp[x].sz=tp[tp[x].ch[0]].sz+tp[x].count+tp[tp[x].ch[1]].sz;}void rotate(int &x,int t){ int y=tp[x].ch[t]; tp[x].ch[t]=tp[y].ch[!t]; tp[y].ch[!t]=x;  update(x); update(y); x=y;}void insert(int &x,int t){   if(! x)    { x=++nodecount; tp[x].key=t; tp[x].wht=rand();      tp[x].count=1; tp[x].ch[0]=tp[x].ch[1]=0;    }else if(tp[x].key==t)  tp[x].count++;    else    { int k=tp[x].key<t; insert(tp[x].ch[k],t);      if(tp[x].wht<tp[tp[x].ch[k]].wht) rotate(x,k);    }    update(x);}void erase(int &x,int t){   if(tp[x].key==t)    {   if(tp[x].count==1)        {   if(! tp[x].ch[0] && ! tp[x].ch[1]) { x=0; return; }            rotate(x,tp[tp[x].ch[0]].wht<tp[tp[x].ch[1]].wht);            erase(x,t);        } else tp[x].count--;    } else erase(tp[x].ch[tp[x].key<t],t);    update(x);}int select(int x,int t){      if(! x) return 0; if(tp[x].key>t) return select(tp[x].ch[0],t);return tp[x].count+tp[tp[x].ch[0]].sz+select(tp[x].ch[1],t);}int a[N],b[N],ord[M][5],lb;int n,m,tt;int search(int x){ int l=1,r=b[0],mid; while (l<=r){ mid=(l+r)>>1;if(b[mid]==x) return mid;  if(b[mid]<x) l=mid+1;  else r=mid-1;}}void treeinsert(int l,int r,int i,int x){insert(tree[IDX(l,r)],x); if(l==r) return; int m=(l+r)>>1;if(i<=m) treeinsert(l,m,i,x); else treeinsert(m+1,r,i,x);}void treedel(int l,int r,int i,int x){erase(tree[IDX(l,r)],x); if(l==r) return; int m=(l+r)>>1;if(i<=m) treedel(l,m,i,x); else treedel(m+1,r,i,x);}int query(int l,int r,int x,int y,int k){ if(l==r) return l; int m=(l+r)>>1;  int ans=select(tree[IDX(l,m)],y)-select(tree[IDX(l,m)],x);  if(ans>=k) return query(l,m,x,y,k); return query(m+1,r,x,y,k-ans);}int main (){scanf("%d",&tt);while (tt--){scanf("%d%d",&n,&m); b[0]=1; lb=0;memset(tree,0,sizeof(tree)); init();for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[++lb]=a[i]; }for(int i=1;i<=m;i++){char s[5]; int x,y,c; scanf("%s",s);if(s[0]=='Q'){ scanf("%d %d %d",&x,&y,&c);  ord[i][1]=1; ord[i][2]=x; ord[i][3]=y; ord[i][4]=c;}else{ scanf("%d %d",&x,&y);  ord[i][1]=2; ord[i][2]=x; ord[i][3]=y; b[++lb]=y;}}sort(b+1,b+1+lb);for(int i=1;i<=lb;i++) if(b[i]!=b[b[0]]) b[++b[0]]=b[i];for(int i=1;i<=n;i++){ a[i]=search(a[i]); treeinsert(1,b[0],a[i],i); }for(int i=1;i<=m;i++){if(ord[i][1]==1)printf("%d\n",b[query(1,b[0],ord[i][2]-1,ord[i][3],ord[i][4])]);else{ treedel(1,b[0],a[ord[i][2]],ord[i][2]);  a[ord[i][2]]=search(ord[i][3]);  treeinsert(1,b[0],a[ord[i][2]],ord[i][2]);}}}return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.