我的树形dp果然是渣。。。

题意:给一棵树,共n(0<n<=15e4)个节点,可在树上进行跳跃,每次跳的最大距离为k(0<k<=5),定义f(s,t)为(dis(s,t)+k)/k,问Σf(s,t),s<t。

解题思路:

  显然是树形dp,问题在于怎么构建状态。

  最简单想到的就是,每到一个节点u,记录其子树中与其距离为d的的节点的数目,即(dis,cnt)对,则答案分两种情况,u到其子节点和以及子节点经过u到子节点,问题变得很简单,计算也不难——但问题在于极端情况下——比如树退化成链,时空复杂度都将高到无法忍受,于是卡在了这里……

  然后看了别人的题解,发现不需要构建(dis,cnt)对,而是构建(dis%k,cnt)对——这样复杂度枚举的最高复杂度也就只是k^2而不是dis^2,,,啊感觉自己宛若一个zz。

  定义,sz(u,i)表示与节点u的距离%k为 i 的节点数目,dp(u,i)表示从u到sz(u,i)中节点的跳数和。

  状态转移如下:

  (1)sz(u,(i+1)%k)+=sz(v,i)

  (2)dp(u,(i+1)%k)+=dp(v,i)  0<i<k

  (3)dp(u,1%k)+=dp(v,0)+sz(v,0)

  显然,与u的子节点v的距离%k大于0的,到v所需跳数与到u所需跳数是相同的(式子(2))。否则跳数需要+1,有sz(v,0)个点,故再加上sz(v,0)(式子(3))。

  接下来是统计答案,分两种情况,一个是u到其子节点,另一个是u到子节点到其它子节点(子节点间的最近公共祖先节点为u)。

  对于第一种,直接res+=Σdp[u][i]即可。

  对于第二种,将之前已经遍历过的子树节点都合并到dp[u][i]与sz[u][i]中,则与新的子树节点v合并时,枚举k1、k2,依次为已遍历过的子树节点与u的距离%k=k1,以及与v的子树中与u的距离%k为k2的节点(语文不好这段贼拗口……k^2的枚举就是这里了),分情况讨论:

  如果k1为0,则dp[u][k1]中则为恰好到达u的跳数(即每一跳距离都是k),则从sz[u][k1]中的节点到达 v的子树中的节点 所需跳数 恰好为二者相加之和,不需额外处理;如果k2为0,同理;当k1与k2都不为0时,考虑k1+k2<=k,则此时说明多计算了一跳,因此需要减去;当k1+k2>k时,恰好符合。

  综上,需要特判的也只有(k1&&k2&&k1+k2<=k)这种情况。

  代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
#define sqr(x) ((x)*(x))
const int N=2e5+;
int head[N],nxt[N<<],to[N<<],cnt;
int n,k,a,b;
ll sz[N][],dp[N][],res;
void init(){
memset(head,-,sizeof(head));
res=cnt=;
memset(sz,,sizeof(sz));
memset(dp,,sizeof(dp));
}
void addEdge(int u,int v){
nxt[cnt]=head[u];
to[cnt]=v;
head[u]=cnt++;
}
void dfs(int u,int pre){
ll tsz[],tdp[]; //用以暂时保存从u到新的v子树节点的数据
for(int e=head[u];~e;e=nxt[e]){
int v=to[e];
if(v==pre) continue;
dfs(v,u);
memset(tsz,,sizeof(tsz));
memset(tdp,,sizeof(tdp));
for(int i=;i<k;i++)
tsz[(i+)%k]+=sz[v][i];
for(int i=;i<k;i++)
tdp[(i+)%k]+=dp[v][i];
tdp[%k]+=dp[v][]+sz[v][];
for(int k1=;k1<k;k1++){
for(int k2=;k2<k;k2++){
res+=dp[u][k1]*tsz[k2]+sz[u][k1]*tdp[k2];
if(k1&&k2&&k1+k2<=k) res-=sz[u][k1]*tsz[k2];
}
}
//将v的子树节点情况合并到u下
for(int i=;i<k;i++)
dp[u][i]+=tdp[i],sz[u][i]+=tsz[i];
}
for(int i=;i<k;i++)
res+=dp[u][i];
sz[u][]++;
}
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&k)){
init();
for(int i=;i<n;i++){
scanf("%d%d",&a,&b);
addEdge(a,b);
addEdge(b,a);
}
dfs(,);
printf("%I64d\n",res);
}
return ;
}

  参考题解:http://www.cnblogs.com/AOQNRMGYXLMV/p/6579771.html

Codeforces 771C的更多相关文章

  1. CodeForces 771C Bear and Tree Jumps 树形DP

    题意: 给出一棵树,一个人可以在树上跳,每次最多跳\(k(1 \leq k \leq 5)\)个点 定义\(f(s,t)\)为从顶点\(s\)跳到顶点\(t\)最少需要跳多少次 求\(\sum\lim ...

  2. python爬虫学习(5) —— 扒一下codeforces题面

    上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...

  3. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  4. 【Codeforces 738C】Road to Cinema

    http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...

  5. 【Codeforces 738A】Interview with Oleg

    http://codeforces.com/contest/738/problem/A Polycarp has interviewed Oleg and has written the interv ...

  6. CodeForces - 662A Gambling Nim

    http://codeforces.com/problemset/problem/662/A 题目大意: 给定n(n <= 500000)张卡片,每张卡片的两个面都写有数字,每个面都有0.5的概 ...

  7. CodeForces - 274B Zero Tree

    http://codeforces.com/problemset/problem/274/B 题目大意: 给定你一颗树,每个点上有权值. 现在你每次取出这颗树的一颗子树(即点集和边集均是原图的子集的连 ...

  8. CodeForces - 261B Maxim and Restaurant

    http://codeforces.com/problemset/problem/261/B 题目大意:给定n个数a1-an(n<=50,ai<=50),随机打乱后,记Si=a1+a2+a ...

  9. CodeForces - 696B Puzzles

    http://codeforces.com/problemset/problem/696/B 题目大意: 这是一颗有n个点的树,你从根开始游走,每当你第一次到达一个点时,把这个点的权记为(你已经到过不 ...

随机推荐

  1. 浅谈微信小程序对于房地产行业的影响

    前几日,我们曾经整理过一篇文章是关于微信小程序对于在线旅游业的影响的一些反思(浅谈微信小程序对OTA在线旅游市场的影响),近日由于生活工作的需要走访了一些房地产的住宅商品房,突然想到微信小程序对于房地 ...

  2. vim基础(一)

    今天看了下兄弟连的VIM讲解,又学了几个新命令,记录一下. 插入与删除 插入 首先还是插入,以前只知道i.今天发现原来还有a\A\i\I\o\O,下面具体说一下: 命令 含义 a 在光标后插入 A 在 ...

  3. window7 上创建定时任务来运行自动化脚本

    跌跌撞撞,坑坑洼洼,终于把公司一个小模块的接口测试脚本写完了,一共有20多个吧!后来发现每天自己去运行一键执行的脚本太麻烦,所以想用windows的定时任务来解决这个问题!今天看了篇文章,所以决定实践 ...

  4. L2-014. 列车调度(带图详解)

    L2-014. 列车调度   火车站的列车调度铁轨的结构如下图所示. Figure 两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道.每趟列车从入口可以选 ...

  5. PAT 1133 Splitting A Linked List

    Given a singly linked list, you are supposed to rearrange its elements so that all the negative valu ...

  6. Spring 源码学习(一)

    工作好多年了,越来越心浮气躁了,好多东西都是一知半解的,所以现在需要静下心来好好学习一门技术. 就选Spring了, spring 设计java 开发的方方面面. 期待目标 对Spring 有个更深层 ...

  7. 20181010关于pt-kill自动杀死运行超长的进程

    转自: http://blog.chinaunix.net/uid-16844903-id-4442030.htmlhttp://blog.chinaunix.net/uid-31396856-id- ...

  8. redis sentinel集群配置及haproxy配置

    ip分布情况: sentinel-1/redis 主 10.11.11.5 sentinel-2/redis 从 10.11.11.7 sentinel-3/redis 从 10.11.11.8 ha ...

  9. 非常适合新手的jq/zepto源码分析08---ajax的封装

    1.现在看看对JSONP的封装 $.ajaxJSONP = function(options, deferred){ if (!('type' in options)) return $.ajax(o ...

  10. NYOJ 16 矩形嵌套 (DAG上的DP)

    矩形嵌套 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描写叙述 有n个矩形,每个矩形能够用a,b来描写叙述.表示长和宽.矩形X(a,b)能够嵌套在矩形Y(c,d)中当且仅当 ...