屑萌新求助左偏树

P2713 罗马游戏

@[peterha](/user/239895) 老哥,你 h 是并查集吧,你用并查集指向当前合并以后分数最低的士兵,你确定这样并查集不会出锅? 不要随便玩并查集啊…… 我现在帮你改了下,已经能过了,做法是并查集正常维护,然后把左偏树的根塞在并查集的根上,具体的是那个 st 数组。 ```cpp #include<bits/stdc++.h> using namespace std; int n,m,h[1000003]; bool f[1000003]; struct node{ int nm,l,r,ds; }t[1000003]; int st[1000003]; int fd(int a){ //并查集路径压缩 if(h[a]!=a) h[a]=fd(h[a]); return h[a]; } int hb(int x,int y){ //合并操作 if(!x||!y) return x+y; if(t[x].nm>t[y].nm) swap(x,y); t[x].r=hb(t[x].r,y); if(t[t[x].l].ds<t[t[x].r].ds) swap(t[x].l,t[x].r); t[x].ds=t[t[x].r].ds+1; return x; } int main(){ scanf("%d",&n); t[0].ds=-1; for(int i=1;i<=n;++i) scanf("%d",&t[i].nm),h[i]=i,st[i]=i; scanf("%d",&m); char op=0; int x=0,y=0; for(int i=1;i<=m;++i){ for(cin>>op;op!='M'&&op!='K';cin>>op); scanf("%d",&x); if(op=='M'){ //操作一,合并 scanf("%d",&y); if(f[x]||f[y]) continue; int a=fd(x),b=fd(y); if(a!=b) h[a]=b,st[b]=hb(st[b],st[a]); } else if(op=='K'){ //操作二,删除 if(f[x]){ printf("0\n"); continue; } x=fd(x);int now=st[x];f[now]=true; printf("%d\n",t[now].nm); st[x]=hb(t[now].l,t[now].r); // t[now].l=t[now].r=t[now].ds=0; } } return 0; } ```
by zjjws @ 2021-04-14 07:40:05


@[zjjws](/user/73551) 应该不用那样大改吧?其实只是并查集的合并写错了: ```cpp if(a!=b) h[x]=h[y]=hb(x,y); ``` ```cpp if(a!=b) h[a]=h[b]=hb(a,b); ```
by Legitimity @ 2021-04-14 21:27:32


@[zjjws](/user/73551) 大感谢,懂了
by Yusani_huh @ 2021-04-14 22:56:35


@[win10](/user/241977) az 我不清楚有没有锅但是这俩东西混一起确实有点恶心。这种写法很危,我猜测在有改点权的时候会挂掉。
by zjjws @ 2021-04-15 07:31:54


@[Legitimity](/user/241977) 感谢!
by sleeping_crawlers @ 2022-03-28 14:17:38


|