洛谷数据非常水,建议去bzoj
我第一眼一看这不是那个POI2011的升级版吗(明明这个是2009年的,应该说那个是这个的弱化版,果然思想差不多。
因为$k$很小,可以考虑每个间隔距离来转移。我们按照传统(雾,其实这里的的名字已经不是很符合定义了,设$cov[i][j]$表示以$i$为根的子树里剩余控制距离为$j$的点还能控制几个点,$unc[i][j]$表示以$i$为根的子树里还没被覆盖的距离等于$j$的点有几个。每次从儿子获取信息后先更新$cov[x][k]$,然后就是这“类”题的关键:$cov$和$unc$这两个数组如何互相抵消。
考虑贪心,对于除了根节点以外的点,我们只让它的$cov[i][j]$去和$unc[i][j-1]$和$unc[i][j]$抵消,也就是只和过了这个点就抵消不了的抵消。可能你会问为什么要抵消距离为$j-1$的点(看起来它们是可以交给父亲抵消的),这是因为我们再往上走一步会导致控制距离减一,实际距离加一,这样一来其实是抵消不了的。
注意在根节点还要把剩下的没抵消掉的抵消.......
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005,K=22; 6 int p[N],noww[2*N],goal[2*N]; 7 long long cov[N][K],unc[N][K]; 8 long long s,k,cst,ans; 9 int n,t1,t2,cnt; 10 void link(int f,int t) 11 { 12 noww[++cnt]=p[f]; 13 goal[cnt]=t,p[f]=cnt; 14 } 15 void DFS(int nde,int fth) 16 { 17 unc[nde][0]=1; 18 for(int i=p[nde];i;i=noww[i]) 19 if(goal[i]!=fth) 20 { 21 DFS(goal[i],nde); 22 for(int j=1;j<=k;j++) 23 { 24 unc[nde][j]+=unc[goal[i]][j-1]; 25 cov[nde][k-j]+=cov[goal[i]][k-j+1]; 26 } 27 } 28 long long tmp=(unc[nde][k]+s-1)/s; 29 ans+=tmp,cov[nde][k]+=tmp*s; 30 for(int i=0;i<=k;i++) 31 if(cov[nde][i]) 32 { 33 for(int j=i;~j;j--) 34 if(i-j<=1||nde==1) 35 { 36 if(cov[nde][i]<=unc[nde][j]) 37 { 38 unc[nde][j]-=cov[nde][i]; 39 cov[nde][i]=0; break; 40 } 41 cov[nde][i]-=unc[nde][j],unc[nde][j]=0; 42 } 43 else break; 44 } 45 } 46 int main () 47 { 48 scanf("%d%lld%lld",&n,&s,&k); 49 for(int i=1;i<n;i++) 50 { 51 scanf("%d%d",&t1,&t2); 52 link(t1,t2),link(t2,t1); 53 } 54 DFS(1,0); 55 for(int i=0;i<=k;i++) 56 cst+=unc[1][i]; 57 printf("%lld",ans+(cst+s-1)/s); 58 return 0; 59 }