[bzoj1086][SCOI2005][王室联邦] (树分块)
Description
“余”人国的国王想重新编制他的国家。他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成
员来管理。他的国家有n个城市,编号为1..n。一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条
直接或间接的道路。为了防止管理太过分散,每个省至少要有B个城市,为了能有效的管理,每个省最多只有3B个
城市。每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。但是该省的任意一个城市到达省会所经
过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。一个城市可以作为多个省的省会。聪明的
你快帮帮这个国王吧!
Input
第一行包含两个数N,B(1<=N<=1000, 1 <= B <= N)。接下来N-1行,每行描述一条边,包含两个数,即这
条边连接的两个城市的编号。
Output
如果无法满足国王的要求,输出0。否则输出数K,表示你给出的划分方案中省的个数,编号为1..K。第二行输
出N个数,第I个数表示编号为I的城市属于的省的编号,第三行输出K个数,表示这K个省的省会的城市编号,如果
有多种方案,你可以输出任意一种。
Sample Input
8 2 1 2 2 3 1 8 8 7 8 6 4 6 6 5
Sample Output
3 2 1 1 3 3 3 3 2 2 1 8
Solution
新技能get,树分块
大致做法如下,深搜整棵树,将沿路点入栈,若栈大小超过了B,则将超过B的部分点弹出,加入一个块,以当前点作为首都
最后把为出栈元素再加入一个栈
这样做块的大小一定不会超过3B
0ms的程序,rank31
//Kaiba_Seto 20170117 //orz cjkmao #include <stdio.h> #include <string.h> #define MaxN 1010 #define MaxBuf 1<<22 #define RG register #define inline __inline__ __attribute__((always_inline)) #define Blue() ((S == T&&(T=(S=B)+fread(B,1,MaxBuf,stdin),S == T)) ? 0 : *S++) char B[MaxBuf],*S=B,*T=B; template<class Type>inline void Rin(RG Type &x) { x=0;RG Type c=Blue(),f=1; for(; c<48||c>57; c=Blue()) if(c==45)f=-1; for(; c>47&&c<58; c=Blue()) x=(x<<1)+(x<<3)+c-48; x*=f; } bool vis[MaxN]; int n,_b,_pb[MaxN],_pb_top,belong[MaxN],block_cnt,block_cap[MaxN]; struct p { p *n; int t; }*f[MaxN]; inline void link(RG int x,RG int y) { static p mem[MaxN<<1],*top=mem; *++top=(p) {f[x],y},f[x]=top; *++top=(p) {f[y],x},f[y]=top; } void dfs(RG int x) { vis[x]=1; RG size_t status=_pb_top; for(RG p *j=f[x]; j; j=j->n) if(!vis[j->t]) { dfs(j->t); if(_pb_top-status >= _b) { block_cap[++block_cnt]=x; while(_pb_top != status) { RG int t=_pb[_pb_top--]; belong[t]=block_cnt; } } } _pb[++_pb_top]=x; } inline void block_solve() { dfs(1); while(_pb_top) { RG int t=_pb[_pb_top--]; belong[t]=block_cnt; } } int main() { Rin(n),Rin(_b); for(RG int i=1; i<n; i++) { RG int x,y; Rin(x),Rin(y); link(x,y); } block_solve(); printf("%d\n",block_cnt); for(RG int i=1; i<=n; i++) printf("%d%c",belong[i],i==n?'\n':' '); for(RG int i=1; i<=block_cnt; i++) printf("%d%c",block_cap[i],i==block_cnt?'\n':' '); fclose(stdin); return 0; }