影片連結:C135 線段樹分治 P5631 最小mex生成樹_嗶哩嗶哩_bilibili
P5631 最小mex生成樹 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
// 線段樹分治 O(nlognlogw) #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define ls (u<<1) #define rs (u<<1|1) #define mid (l+r>>1) #define N 2000005 int n,m,mx,top; int a[N],b[N],w[N]; int p[N],siz[N]; vector<int>tr[400005]; //節點 struct node{ int x,y; }st[N<<1]; //棧 void insert(int u,int l,int r,int L,int R,int i){ if(l>R||r<L) return; if(L<=l&&r<=R) return tr[u].push_back(i); insert(ls,l,mid,L,R,i); insert(rs,mid+1,r,L,R,i); } int find(int x){ //查詢根 return p[x]==x?x:find(p[x]); } void merge(int x,int y){ //合併集合 x=find(x),y=find(y); if(x==y) return; if(siz[x]>siz[y]) swap(x,y); st[++top]={x,y}; p[x]=y; siz[y]+=siz[x]; } void solve(int u,int l,int r){ int now=top; for(auto i:tr[u]) merge(a[i],b[i]); if(l==r){ if(siz[find(1)]==n) printf("%d\n",l),exit(0); } else solve(ls,l,mid),solve(rs,mid+1,r); while(top>now){ //撤銷合併 node s=st[top--]; p[s.x]=s.x; siz[s.y]-=siz[s.x]; } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) p[i]=i,siz[i]=1; for(int i=1;i<=m;++i){ scanf("%d%d%d",&a[i],&b[i],&w[i]); mx=max(mx,w[i]+1); } for(int i=1;i<=m;++i){ insert(1,0,mx, 0,w[i]-1, i); insert(1,0,mx, w[i]+1,mx,i); } solve(1,0,mx); }