1. 程式人生 > >BZOJ1455: 羅馬遊戲

BZOJ1455: 羅馬遊戲

set using 插入 != true 子節點 平面 ref 希望

【傳送門:BZOJ3477】


簡要題意:

  羅馬皇帝很喜歡玩殺人遊戲。 他的軍隊裏面有n個人,每個人都是一個獨立的團。最近舉行了一次平面幾何測試,每個人都得到了一個分數。 皇帝很喜歡平面幾何,他對那些得分很低的人嗤之以鼻。他決定玩這樣一個遊戲。 它可以發兩種命令: 1. Merger(i, j)。把i所在的團和j所在的團合並成一個團。如果i, j有一個人是死人,那麽就忽略該命令。 2. Kill(i)。把i所在的團裏面得分最低的人殺死。如果i這個人已經死了,這條命令就忽略。 皇帝希望他每發布一條kill命令,下面的將軍就把被殺的人的分數報上來。(如果這條命令被忽略,那麽就報0分)


題解:

  左偏樹的模版題

  左偏樹就是合並堆

  性質:

  一、節點的關鍵值大於等於兩個兒子節點的關鍵值(堆的性質)

  二、定義節點到最近的葉節點的距離為節點距離,任意節點的左兒子的距離大於右兒子的距離(左偏樹的性質)

  左偏樹在實現插入操作時總是從右側插入,也就是總是讓短的一側生長,如果右側長於左側,那麽交換左右側,繼續從右側生長

  綜上,都是hzwer(orz)的原話


參考代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include
<cmath> using namespace std; int fa[1100000],l[1100000],r[1100000],dep[1100000],d[1100000]; bool v[1100000]; int findfa(int x) { if(x!=fa[x]) fa[x]=findfa(fa[x]); return fa[x]; } int merge(int x,int y) { if(x==0) return y; if(y==0) return x; if(d[x]>d[y]) swap(x,y); r[x]=merge(r[x],y);
if(dep[l[x]]<dep[r[x]]) swap(l[x],r[x]); dep[x]=dep[r[x]]+1; return x; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&d[i]); for(int i=1;i<=n;i++) fa[i]=i; memset(v,true,sizeof(v)); dep[0]=-1; int m; scanf("%d",&m); for(int i=1;i<=m;i++) { char st[2]; scanf("%s",st+1); if(st[1]==M) { int x,y; scanf("%d%d",&x,&y); if(v[x]==false||v[y]==false) continue; int fx=findfa(x),fy=findfa(y); if(fx!=fy) fa[fx]=fa[fy]=merge(fx,fy); } else { int x; scanf("%d",&x); if(v[x]==false){printf("0\n");continue;} int fx=findfa(x); printf("%d\n",d[fx]); v[fx]=false; fa[fx]=merge(l[fx],r[fx]); fa[fa[fx]]=fa[fx]; } } return 0; }

BZOJ1455: 羅馬遊戲