我的树形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. illuminate/routing 源码分析之注册路由

    我们知道,在 Laravel 世界里,外界传进来一个 Request 时,会被 Kernel 处理并返回给外界一个 Response.Kernel 在处理 Request 时,会调用 illumina ...

  2. python爬虫27 | 当Python遇到MongoDB的时候,存储av女优的数据变得如此顺滑爽~

    上次 我们知道了怎么操作 MySQL 数据库 python爬虫26 | 把数据爬取下来之后就存储到你的MySQL数据库. MySQL 有些年头了 开源又成熟又牛逼 所以现在很多企业都在使用 MySQL ...

  3. 洛谷 4216 BZOJ 4448 [SCOI2015]情报传递

    [题解] 每个情报员的危险值val[i]应该是一个分段函数,前面一段是平行于x轴的横线,后面一段是一次函数.我们可以用fx(t)=t-b[x]表示这个一次函数.每次询问一条链上fx(t)大于c的点的个 ...

  4. HDU 5291 Candy Distribution

    Candy Distribution Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  5. 初次使用Let's encrypt

    wget --no-check-certificate -O shadowsocks.sh https://raw.githubusercontent.com/teddysun/shadowsocks ...

  6. Non-inclusive cache method using pipelined snoop bus

    A non-inclusive cache system includes an external cache and a plurality of on-chip caches each havin ...

  7. 洛谷—— P1187 3D模型

    https://www.luogu.org/problem/show?pid=1187 题目描述 一座城市建立在规则的n×m网格上,并且网格均由1×1正方形构成.在每个网格上都可以有一个建筑,建筑由若 ...

  8. KonBoot – 只要5K映象文件轻易绕过您的WindowsXP/VISTA/7系统的密码

    http://pannisec.diandian.com/?tag=konBoot 这个东西是我昨晚点击了QQ弹窗的那个SOSO问题后,有人问我如何破解Windows登陆密码,且不可以用net命令创建 ...

  9. zoj 月赛

    Wumpus Time Limit: 2 Seconds      Memory Limit: 65536 KB One day Leon finds a very classic game call ...

  10. 从内核源代码配置文件预測泛泰新品(A920 ?)

    泛泰的IRON2 A910刚公布不久, 但近期在最新的泛泰890的内核源代码的config文件中又看到了这种编号,例如以下图: 图上ef63s 明显是A910S. 但这ef65s 又是什么呢, 看到这 ...