题目
题目链接:https://www.luogu.com.cn/problem/P2325
“余”人国的国王想重新编制他的国家。他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理。
他的国家有 (N) 个城市,编号为 (1ldots N)。
一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路。
为了防止管理太过分散,每个省至少要有 (B) 个城市。
为了能有效的管理,每个省最多只有 (3 imes B) 个城市。
每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。
但是该省的任意一个城市到达省会所经过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。
一个城市可以作为多个省的省会。
聪明的你快帮帮这个国王吧!
(n,Bleq 10^3)。
思路
写完了才知道这个是树分块板子题。
对于一个点 (x),我们先递归它的儿子 (y)。经过若干划分后,(y) 返回的未被划分的点集是一个包含 (y) 在内的连通块。如果 (x) 的若干子树未被划分的点集大小超过 (B) 了,那么就把这些点全部划分进一个省,并把省会设为 (x)。
处理完 (x) 后把 (x) 加入点集。
显然这样操作后我们会得到若干个大小不超过 (2B-1) 的集合以及最后未被划分的点集,显然这个点集大小不超过 (B),直接扔进最后一个集合里即可。
时间复杂度 (O(n))。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m,B,tot,head[N],bel[N],pos[N];
stack<int> st;
struct edge
{
int next,to;
}e[N*2];
void add(int from,int to)
{
e[++tot]=(edge){head[from],to};
head[from]=tot;
}
void dfs(int x,int fa)
{
int cnt=st.size();
for (int i=head[x];~i;i=e[i].next)
{
int v=e[i].to;
if (v!=fa)
{
dfs(v,x);
if (st.size()-cnt>=B)
{
pos[++m]=x;
for (;st.size()>cnt;st.pop())
bel[st.top()]=m;
}
}
}
st.push(x);
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&B);
for (int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(1,0);
for (;st.size();st.pop())
bel[st.top()]=m;
cout<<m<<"
";
for (int i=1;i<=n;i++) cout<<bel[i]<<' ';
cout<<"
";
for (int i=1;i<=m;i++) cout<<pos[i]<<' ';
return 0;
}