【洛谷7215】[JOISC2020] 首都(點分治+BFS)
阿新 • • 發佈:2021-06-24
- 給定一棵\(n\)個點的樹,樹上的第\(i\)個節點屬於第\(c_i\)個城市。
- 要求合併儘可能少的城市,使得存在一個城市在樹上形成一個連通塊。
- \(n\le2\times10^5\)
點分治+\(BFS\)
對於這種樹上連通塊問題,可以考慮點分治,強制當前的分治中心在我們所選的連通塊中。
於是我們首先加入與它同色的所有節點作為起始點開始\(BFS\),每次判斷隊首節點的父節點是否已經被訪問過,若沒有則將與父節點同色的所有點都加入佇列。
如果在這一過程中出現了當前分治連通塊之外的點,那麼答案肯定已經被考慮過了,直接結束\(BFS\)。否則,就可以在\(BFS\)結束後更新答案。
這樣一來每次\(BFS\)
程式碼:\(O(nlogn)\)
#include<bits/stdc++.h> #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> #define Reg register #define RI Reg int #define Con const #define CI Con int& #define I inline #define W while #define N 200000 #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y) using namespace std; int n,k,a[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[N<<1];vector<int> p[N+5];vector<int>::iterator it; namespace FastIO { #define FS 100000 #define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++) char oc,FI[FS],*FA=FI,*FB=FI; Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));} }using namespace FastIO; int rt,Sz[N+5],Mx[N+5],used[N+5];I void GetRt(CI x,CI lst,RI s)//找重心 { Sz[x]=1,Mx[x]=0;for(RI i=lnk[x];i;i=e[i].nxt) !used[e[i].to]&& e[i].to^lst&&(GetRt(e[i].to,x,s),Sz[x]+=Sz[e[i].to],Mx[x]=max(Mx[x],Sz[e[i].to])); (Mx[x]=max(Mx[x],s-Sz[x]))<Mx[rt]&&(rt=x); } int tg[N+5],fa[N+5];I void Mark(CI x,CI t)//標記在分治連通塊中,記錄父節點 { tg[x]=t;for(RI i=lnk[x];i;i=e[i].nxt) !used[e[i].to]&&tg[e[i].to]^t&&(fa[e[i].to]=x,Mark(e[i].to,t),0); } int ans=1e9,vis[N+5],q[N+5];I void Solve(RI x)//點分治 { #define Push(A) vis[A]=x;for(it=p[A].begin();it!=p[A].end();++it) if(tg[*it]^x) goto End;else q[++T]=*it;//加入A顏色的所有點 RI k,c=0,H=1,T=0;used[x]=1,Mark(x,x);Push(a[x]);W(H<=T) if((k=q[H++])^x&&vis[a[fa[k]]]^x) {++c;Push(a[fa[k]]);}//BFS ans=min(ans,c);End:for(RI i=lnk[x];i;i=e[i].nxt) !used[e[i].to]&&(GetRt(e[i].to,rt=0,Sz[e[i].to]),Solve(rt),0);//更新答案;遞迴分治 } int main() { RI i,x,y;for(read(n),read(k),i=1;i^n;++i) read(x),read(y),add(x,y),add(y,x); for(i=1;i<=n;++i) read(a[i]),p[a[i]].push_back(i);return Mx[0]=1e9,GetRt(1,rt=0,n),Solve(rt),printf("%d\n",ans),0; }