题目:http://acm.hdu.edu.cn/showproblem.php?pid=1512
很简单的左偏树;
但突然对 rt 的关系感到混乱,改了半天才弄对;
注意是多组数据!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const maxn=1e5+5; int n,m,s[maxn],rt[maxn],ls[maxn],rs[maxn],dis[maxn]; int find(int x){while(rt[x])x=rt[x]; return x;} int merge(int x,int y) { if(!x||!y)return x+y; if(s[x]<s[y])swap(x,y); rs[x]=merge(rs[x],y); rt[rs[x]]=x; if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]); if(rs[x])dis[x]=dis[rs[x]]+1; else dis[x]=0; // rt[rs[x]]=rt[ls[x]]=x; return x; } void clr(int x){rt[x]=0; rs[x]=0; ls[x]=0;} int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++)scanf("%d",&s[i]),ls[i]=rs[i]=dis[i]=rt[i]=0; scanf("%d",&m); for(int i=1,x,y,u,v,t1,t2;i<=m;i++) { scanf("%d%d",&x,&y); u=find(x); v=find(y); if(u==v){printf("-1 "); continue;} rt[ls[u]]=0; rt[rs[u]]=0; rt[ls[v]]=0; rt[rs[v]]=0; //! t1=merge(ls[u],rs[u]); t2=merge(ls[v],rs[v]); clr(u); clr(v);//! s[u]>>=1; s[v]>>=1; merge(u,t1); merge(v,t2); printf("%d ",s[merge(find(u),find(v))]);//find() } } return 0; }
还可以把 rt 当并查集用,因为并查集实际上也是树,似乎更简洁;
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const maxn=1e5+5; int n,m,s[maxn],rt[maxn],ls[maxn],rs[maxn],dis[maxn]; int find(int x){return rt[x]==x?x:rt[x]=find(rt[x]);} int merge(int x,int y) { if(!x||!y)return x+y; if(s[x]<s[y])swap(x,y); rs[x]=merge(rs[x],y); rt[rs[x]]=x; if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]); if(rs[x])dis[x]=dis[rs[x]]+1; else dis[x]=0; // rt[rs[x]]=rt[ls[x]]=x; return x; } int del(int x) { int l=ls[x],r=rs[x]; rt[l]=l; rt[r]=r; ls[x]=rs[x]=dis[x]=0; return merge(l,r); } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++)scanf("%d",&s[i]),rt[i]=i,ls[i]=rs[i]=dis[i]=0; scanf("%d",&m); for(int i=1,x,y,u,v,t1,t2;i<=m;i++) { scanf("%d%d",&x,&y); u=find(x); v=find(y); if(u==v){printf("-1 "); continue;} s[u]>>=1; t1=del(u),t1=merge(u,t1); s[v]>>=1; t2=del(v),t2=merge(v,t2); printf("%d ",s[merge(t1,t2)]);//find() } } return 0; }