Codeforces 161D Distance in Tree

题目大意:给出一棵n个节点的树,统计树中长度为k的路径的条数(1<=n<=50000 , 1<=k<=500)

思路:树分治!

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
int n,K,son[500005],F[500005],sum;
ll ans;
int c[500005],pd[500005],vis[500005],A[500005];
int sz,dis[500005],root,mxdeep,deep[500005];
int tot,go[500005],first[500005],next[500005];
void insert(int x,int y){
    tot++;
    go[tot]=y;
    next[tot]=first[x];
    first[x]=tot;
}
void add(int x,int y){
    insert(x,y);insert(y,x);
}
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
    while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
    return t*f;
}
void findroot(int x,int fa){
    son[x]=1;F[x]=0;
    for (int i=first[x];i;i=next[i]){
        int pur=go[i];
        if (pur==fa||vis[pur]) continue;
        findroot(pur,x);
        F[x]=std::max(F[x],son[pur]);
        son[x]+=son[pur];
    }
    F[x]=std::max(F[x],sum-son[x]);
    if (F[x]<F[root]) root=x;
}
void Dfs(int x,int fa){
    mxdeep=std::max(mxdeep,deep[x]);
    for (int i=first[x];i;i=next[i]){
        int pur=go[i];
        if (fa==pur||vis[pur]) continue;
        deep[pur]=deep[x]+1;
        Dfs(pur,x);
    }
}
void bfs(int x){
    pd[x]=sz;
    int h=1,t=1;c[1]=x;dis[x]=1;
    while (h<=t){
        int now=c[h++];
        for (int i=first[now];i;i=next[i]){
            int pur=go[i];
            if (pd[pur]==sz||vis[pur]) continue;
            dis[pur]=dis[now]+1;
            c[++t]=pur;
            pd[pur]=sz;
        }
    }
    for (int i=1;i<=t;i++)
     if (K>=dis[c[i]])
     ans+=A[K-dis[c[i]]];
    for (int i=1;i<=t;i++)
     A[dis[c[i]]]++;
}
void solve(int x,int fa){
    vis[x]=1;
    mxdeep=0;
    deep[x]=0;
    Dfs(x,0);
    for (int i=0;i<=mxdeep;i++)
     A[i]=0;
    A[0]=1;
    sz++;
    for (int i=first[x];i;i=next[i]){
        int pur=go[i];
        if (pur==fa||vis[pur]) continue;
        bfs(pur);
    }
    int cnt=sum;
    for (int i=0;i<=mxdeep;i++)
     A[i]=0;
    for (int i=first[x];i;i=next[i]){
        int pur=go[i];
        if (pur==fa||vis[pur]) continue;
        root=0;
        if (son[pur]>son[x]) sum=cnt-son[x];
        else sum=son[pur];
        findroot(pur,x);
        solve(root,x);
    }
}
int main(){
    n=read();K=read();
    for (int i=1;i<n;i++){
        int x=read(),y=read();
        add(x,y);
    }
    F[0]=0x7fffffff;root=0;sum=n;
    findroot(1,0);
    solve(root,0);
    printf("%I64d\n",ans);
}
时间: 2024-10-11 17:48:45

Codeforces 161D Distance in Tree的相关文章

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

CodeForces 161D Distance in Tree【树形DP】

<题目链接> 题目大意:一颗无向无环树,有n个顶点,求其中距离为k的点对数是多少,(u,v)与(v,u)为同一点对. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define N int(5e4+10) 7 int n,k,ans,cnt; 8 int dp[N][510],head[N]; 9 struct Edge{

CF 161D Distance in Tree 树形DP

一棵树,边长都是1,问这棵树有多少点对的距离刚好为k 令tree(i)表示以i为根的子树 dp[i][j][1]:在tree(i)中,经过节点i,长度为j,其中一个端点为i的路径的个数dp[i][j][0]:在tree(i)中,经过节点i,长度为j,端点不在i的路径的个数 则目标:∑(dp[i][k][0]+dp[i][k][1])初始化:dp[i][0][1]=1,其余为0 siz[i]:tree(i)中,i与离i最远的点的距离递推:dp[i][j][0]+=dp[i][j-l][1]*dp[

codeforces161D - Distance in Tree 树形dp

题意:给你一棵树,问你树中距离为k的有多少种情况. 解题思路:树形dp  维护每个节点(1-K)深度的情况, 解题代码: 1 // File Name: 161d.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月03日 星期日 19时20分10秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #incl

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

Educational Codeforces Round 25 G. Tree Queries

题目链接:Educational Codeforces Round 25 G. Tree Queries 题意: 给你一棵树,一开始所有的点全是黑色,有两种操作. 1 x 将x这个点变为黑色,保证第一个操作是这个. 2 x 询问x到任意黑色的点的简单路径上的最小节点编号. 题解: 首先将一个变为黑色的点当成树根,然后dfs一下,预处理出所有点的答案. 然后开一个变量记录一下当前变黑的点的答案cur=min(cur,dp[x]). 每次询问的时候答案就是min(cur,dp[x]). 如果觉得很神

Codeforces.280C.Game on Tree(期望)

题目链接 参考:浅谈期望的线性性(可加性) Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望(这个的前半部分分析并没有看..) \(Description\) 给你一棵有\(n\)个白点的有根树,每次随机选择一个点,将它和它的子树中所有点染黑. 问期望操作多少次后所有点都被染黑? \(Solution\) 期望好玄啊..(好吧是我太弱) 因为概率具有可加性,一棵树可以分解为多棵子树,而子树分解的最终状态就是点,所以我们可以计算每个点的期望操作次

codeforces 161 D. Distance in Tree(树形dp)

题目链接:http://codeforces.com/problemset/problem/161/D 题意:给出一个树,问树上点到点的距离为k的一共有几个. 一道简单的树形dp,算是一个基础题. 设dp[i][len]表示i为根距离为len的一共有几个点. 一般的树形dp都是先dfs然后再更新dp的值,注意按这样写就行了.而且一般的树形dp都是设dp[i][k]i为根,k为条件. void dfs(int u , int pre) { int len = vc[u].size(); dp[u]