[BZOJ1086][Luogu2325]王室联邦--(树上分块)

1.ORZ

orz一下分块算法,orz一下vfk大佬(本题参考了vfk大佬的随笔)。

2.bzoj传送门,luogu传送门

3.题目大意:

本题其实特别有意思,我是在做一道叫糖果公园的题时,翻vfk的博客时被推荐先做的这道题。
回到正题,首先在一个有n(n<=1000)座城市的国家中,它由n-1条道路构成一棵树,国王要求划分省份,给定一个B(B<=n),要求在每个省中的城市数大于等于B,小与等于3B,并且对于每一个省需要规定一个省会(可以不再省内,且同一座城可用做多个省会),
对于一个省的每座城市,从其到其所在省的省会上的路径上的所有城市应均与其同省,求划分省数,省会,以及每座城市所在省。

4.解题思路:

总体思路:DFS。
首先先选任意一个节点为根节点开始DFS,对于一个节点u的DFS,先去搜其儿子vi,若这时返回的等待序列长度大于等于B,便可以划分一个省份,等扫完所有儿子后再将自己加入等待序列,。但会有一个问题,到了最后返回到根节点,等待序列中的个数可能小于B,但不用担心,我们可以直接把剩下的序列中的城市直接加入最后一个划分的省份,证明如下:显然在之前每个省份的城市数<2B,而最后等待序列中的城市数<B,所以把剩余的加入后,最后一个省份的城市数也会小于3B。

5.贴代码啦!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define For(i,j,k) for(int i=j;i<=k;++i)
#define Dor(i,j,k) for(int i=j;i>=k;--i)
#define Ror(i,x) for(int i=head[x];i;i=e[i].nxt)
#define fin(s) freopen(s".in","r",stdin)
#define fout(s) freopen(s".out","w",stdout)
using namespace std;
const int N=1e3+10;
struct edge{
    int to,nxt;
}e[N<<1];
int tot,head[N];
inline void add(int x,int y){
    e[++tot]=(edge){y,head[x]},head[x]=tot;
    e[++tot]=(edge){x,head[y]},head[y]=tot;
}
int n,B,bot,siz,st[N],cnt,rt[N],b[N];
void dfs(int x,int f){
    int bot=siz;
    Ror(i,x){
        int to=e[i].to;
        if(to==f)continue;
        dfs(to,x);
        if(siz-bot>=B){
            rt[++cnt]=x;
            while(siz>bot)b[st[siz--]]=cnt;
        }
    }
    st[++siz]=x;
}
int main(){
    fin("luogu2325");
    fout("luogu2325");
    int x,y;
    scanf("%d%d",&n,&B);
    For(i,1,n-1){
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    dfs(1,1);
    while(siz)b[st[siz--]]=cnt;
    printf("%d\n",cnt);
    For(i,1,n)printf("%d ",b[i]);
    puts("");
    For(i,1,cnt)printf("%d ",rt[i]);
    return 0;
}

6.总结:

树上分块是树上莫队的基础,因此将这题吃透很重要。

posted @ 2018-05-21 21:44  Meteror  阅读(...)  评论(... 编辑 收藏