1. 程式人生 > 實用技巧 >【HNOI2012】永無鄉 題解(並查集+線段樹合併)

【HNOI2012】永無鄉 題解(並查集+線段樹合併)

題目連結

給定一張含$n$個點$m$條邊的無向圖,每個點有一個重要指數$a_i$。有兩種操作:1.在$x$和$y$之間連一條邊;2.求$x$所在連通塊中重要程度第$k$小的點。

---------------------------------

維護第$k$小,很容易想到權值線段樹。看到合併二字,可以想到用線段樹合併的方法。維護連通塊可以用並查集做。

注意並查集合並的方向和線段樹合併的方向要一致。查詢的時候要先找出並查集的根再查詢。

程式碼:

#include<bits/stdc++.h>
using namespace std;
int n,m,q,fa[100005],id[10000005],rt[100005
],tot; struct node { int ls,rs,sum; }tree[10000005]; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } inline int find(int x) { if (x==fa[x]) return x; return fa[x]=find(fa[x]); } inline
int build(int index,int l,int r,int pos,int idx) { if (!index) index=++tot; if (l==r){id[index]=idx;tree[index].sum++;return index;} int mid=(l+r)>>1; if (pos<=mid) tree[index].ls=build(tree[index].ls,l,mid,pos,idx); else tree[index].rs=build(tree[index].rs,mid+1,r,pos,idx); tree[index].sum
=tree[tree[index].ls].sum+tree[tree[index].rs].sum; return index; } inline int merge(int x,int y,int l,int r) { if (!x) return y; if (!y) return x; if (l==r){if (id[y]){id[x]=id[y];tree[x].sum+=tree[y].sum;}return x;} int mid=(l+r)>>1; tree[x].ls=merge(tree[x].ls,tree[y].ls,l,mid); tree[x].rs=merge(tree[x].rs,tree[y].rs,mid+1,r); tree[x].sum=tree[tree[x].ls].sum+tree[tree[x].rs].sum; return x; } inline int query(int index,int x,int l,int r) { if (tree[index].sum<x||!index) return 0; if (l==r) return id[index]; int mid=(l+r)>>1,ans; if (x<=tree[tree[index].ls].sum) ans=query(tree[index].ls,x,l,mid); else ans=query(tree[index].rs,x-tree[tree[index].ls].sum,mid+1,r); return ans; } int main() { n=read(),m=read(); for (int i=1;i<=n;i++) { fa[i]=i;int x=read(); rt[i]=build(rt[i],1,n,x,i); } for (int i=1;i<=m;i++) { int x=read(),y=read(); x=find(x),y=find(y); fa[y]=x; rt[x]=merge(rt[x],rt[y],1,n); } q=read(); while(q--) { char c;cin>>c; int x=read(),y=read(); if (c=='B') { x=find(x),y=find(y); if (x==y) continue; fa[y]=x; rt[x]=merge(rt[x],rt[y],1,n); } else { x=find(x); int ans=query(rt[x],y,1,n); if (!ans) printf("-1\n"); else printf("%d\n",ans); } } return 0; }