洛谷 P2325 王室联邦(分块)

题目链接:

https://www.luogu.org/problemnew/show/P2325

题意:

给你一个含 n n n个点的树,让你给树分块,每一块之间的点要不经过其他块而连通,每一块的大小 S S S,保证 B &lt; = S &lt; = 3 B B&lt;=S&lt;=3B B<=S<=3B,输出可以分成的块数,并输出编号 i i i节点对应块编号,输出每个块的中的任意一个节点;

分析:

推荐一篇写的很好的博客:http://old.orzsiyuan.com/articles/problem-SCOI-2005-Royal-Commonwealth/
建议模拟一下在这里插入图片描述这就是单个块最大可能节点数,整个 d f s dfs dfs过程由最左边转移到中间,然后遍历结束中间那颗子树,此时栈里相对来说剩下 2 B − 1 2B-1 2B1个节点,然后便将这 2 B − 1 2B-1 2B1个分成一块,当访问第三课子树时,剩下不足B个,将根节点入栈后便退出 d f s dfs dfs,然后将栈里剩余的B个分给之前的最后一块,那么最后一块就是 3 B − 1 3B-1 3B1个;(仅供个人理解)
听说是专门为学习树上莫队而生的习题;

代码:
// luogu-judger-enable-o2
#include <iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
#define maxn 1009

struct edge{
    int u,v,next;
}e[2*maxn];

int cnt,head[maxn];

void add(int u,int v){
    e[cnt].u=u,e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}

int top,n,b,num[maxn],cot,st[maxn],sc[maxn];

void  dfs(int x,int fa){
    int now=top;
    for(int i=head[x];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==fa)continue;
        dfs(v,x);
        if(top-now>=b){
            sc[++cot]=x;
            while(top!=now)
                num[st[top--]]=cot;
        }
    }
    st[++top]=x;
}
int main()
{
    cin>>n>>b;
    int a,b;
    memset(head,-1,sizeof(head));
    for(int i=0;i<n-1;i++){
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    dfs(1,0);
    while(top)num[st[top--]]=cot;
    cout<<cot<<endl;
    for(int i=1;i<=n;i++)
        cout<<num[i]<<" ";
    cout<<endl;
    for(int i=1;i<=cot;i++)
        cout<<sc[i]<<" ";
    return 0;
}

我们坚持一件事情,并不是因为这样做了会有效果,而是坚信,这样做是对的。
——哈维尔

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值