zoukankan      html  css  js  c++  java
  • 【洛谷7215】[JOISC2020] 首都(点分治+BFS)

    点此看题面

    • 给定一棵(n)个点的树,树上的第(i)个节点属于第(c_i)个城市。
    • 要求合并尽可能少的城市,使得存在一个城市在树上形成一个连通块。
    • (nle2 imes10^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
    ",ans),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    感触
    儿子会走了
    OLB(outlook bar)控件开发计划
    又要上班了
    OLB(outlook bar)控件开发计划
    将Vim打造成完美的IDE神器
    简明 Vim 练级攻略
    Java , C , C++ ,PHP, python 运算符优先级对照表
    史上最强的vimrc文件
    vim学习资料汇总
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu7215.html
Copyright © 2011-2022 走看看