Description
给你一棵树,现在要建立一些消防站,有以下要求: 1. 消防站要建立在节点上,每个节点可能建立不只一个消防站。 2.
每个节点应该被一个消防站管理,这个消防站不一定建立在该节点上。 3. 每个消防站可以管理至多s个节点。 4.
消防站只能管理距离(两点间最短路径的边数)不超过k的结点。请问至少要设立多少个消防站。
Input
第一行n,s,k。接下来n-1行每行xi,yi描述一条边连接xi与yi。 1<=n<=100000 1<=s<=n 1<=k<=20
1<=xi
Output
一个数,最少的消防站个数。
Sample Input
12 3 1
1 12
3 8
7 8
8 9
2 12
10 12
9 12
4 8
5 8
8 11
6 8
Sample Output
4
题解
玄妙贪心
对于一个消防站的设立 肯定是在能管理所有子树的情况下 设的越高越好
那对于一个点 只有与他相距是K层的点是必须要染的
设状态 c [ i ] [ j ] c[i][j] c[i][j]表示i点,相距j层的还有多少可以染的点
状态 n e d [ i ] [ j ] ned[i][j] ned[i][j]表示点i,相距j层的还有多少要染的点
每一次,只有在迫不得已要染色的时候,才让子树中能对上面做贡献的点去对别的点做贡献
相当于只有在层数小于等于1的时候必须染色
否则回到父亲节点的时候,这个点已经不能对那个需要染色的点做贡献了
其它的就直接给回父亲节点,因为他们在父亲节点那里也可以被染色
总的来说
就是 在迫不得已的情况下才染色
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
struct node{int x,y,next;}a[211000];int len,last[111000];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
LL c[110000][25],ned[110000][25];
int n,S,K,ans;
void treedp(int x,int fa)
{
ned[x][0]++;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa)
{
treedp(y,x);
for(int i=0;i<K;i++)c[x][i]+=c[y][i+1],ned[x][i+1]+=ned[y][i];
}
}
if(ned[x][K])
{
LL s=ceil((double)ned[x][K]/S);ans+=s;
c[x][K]+=s*S-ned[x][K];ned[x][K]=0;
}
for(int i=0;i<=K;i++)
{
LL &tmp=c[x][i];
if(tmp&&ned[x][i])
{
if(tmp>=ned[x][i])tmp-=ned[x][i],ned[x][i]=0;
else ned[x][i]-=tmp,tmp=0;
}
if(tmp&&i-1>=0&&ned[x][i-1])
{
if(tmp>=ned[x][i-1])tmp-=ned[x][i-1],ned[x][i-1]=0;
else ned[x][i-1]-=tmp,tmp=0;
}
}
}
int main()
{
n=read();S=read();K=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ins(x,y);ins(y,x);
}
treedp(1,0);
for(int i=0;i<=K;i++)
{
LL &tmp=c[1][i];
for(int j=0;j<=i&&tmp;j++)
if(ned[1][j]&&tmp)
{
if(tmp>=ned[1][j])tmp-=ned[1][j],ned[1][j]=0;
else ned[1][j]-=tmp,tmp=0;
}
}
LL s=0;
for(int i=0;i<=K;i++)s+=ned[1][i];
ans+=ceil((double)s/S);
printf("%d\n",ans);
return 0;
}