【洛谷P2325】王室联邦
题目
题目链接:https://www.luogu.com.cn/problem/P2325
“余”人国的国王想重新编制他的国家。他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理。
他的国家有 \(N\) 个城市,编号为 \(1\ldots N\)。
一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路。
为了防止管理太过分散,每个省至少要有 \(B\) 个城市。
为了能有效的管理,每个省最多只有 \(3\times B\) 个城市。
每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。
但是该省的任意一个城市到达省会所经过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。
一个城市可以作为多个省的省会。
聪明的你快帮帮这个国王吧!
\(n,B\leq 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<<"\n";
for (int i=1;i<=n;i++) cout<<bel[i]<<' ';
cout<<"\n";
for (int i=1;i<=m;i++) cout<<pos[i]<<' ';
return 0;
}