点分治【bzoj1468】 Tree

点分治【bzoj1468】 Tree

Description

给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

Input

N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

Output

一行,有多少对点之间的距离小于等于k

点分治开始入门。

点分治,主要是解决形如:给你一棵树,求树上满足XX条件的点对的对数。

所以说应对的问题很多时候都和树形DP相同。

首先告诉自己,分治是高效的算法。

想一下,平时在面对普通的分治问题,每次肯定都是半分,直到成为小问题,然后再分别解决。

为了保证点分治的高效,所以我们每一次应该将当前问题分成最平均的两个问题,放到树上就是指我们要将当前的树分成大小最平均的几棵。

那么就可以引入一个概念:树的重心。定义是在树上找一个点作为根,使得子树中的size最大者最小,这样我们就可以很好的将树平均分。

所以解决点分治问题的基本思路也就有了:

? 我们从整棵树开始,每一次找到当前树的重心并且以他为根,也就是将无根树转成有根树,然后对于当前的树,我们只对与当前树的根的点对进行处理。

? 对于这道题来说,就是找到路径经过当前根的点对,去统计这些点对中符合条件的数量对答案作出贡献。

? 然后对于每个子树,向下分治,继续找重心……

code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int wx=40017;
inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    return sum*f;
}
int n,m,ans,num,root,k,tmp;
int head[wx],dis[wx],size[wx];
int f[wx],vis[wx];
int temp[wx];
struct e{
    int nxt,to,dis;
}edge[wx*2];
void add(int from,int to,int dis){
    edge[++num].nxt=head[from];
    edge[num].to=to;
    edge[num].dis=dis;
    head[from]=num;
}
void getroot(int u,int fa){
    size[u]=1;f[u]=0;
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa||vis[v])continue;
        getroot(v,u);
        size[u]+=size[v];
        f[u]=max(f[u],size[v]);
    }
    f[u]=max(f[u],tmp-size[u]);
    if(f[root]>f[u])root=u;
}
void dfs(int u,int fa){
    temp[++temp[0]]=dis[u];
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa||vis[v])continue;dis[0]++;
        dis[v]=dis[u]+edge[i].dis;
        dfs(v,u);
    }
}
int calc(int u,int now){
    dis[u]=now;temp[0]=0;dfs(u,0);
    int l=1,r=temp[0];int re=0;
    sort(temp+1,temp+temp[0]+1);
    while(l<r){
        if(temp[r]+temp[l]<=k)re+=r-l,l++;
        else r--;
    }
    return re;
}
void slove(int u){
    vis[u]=1;ans+=calc(u,0);
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(vis[v])continue;
        ans-=calc(v,edge[i].dis);
        root=0;tmp=size[v];getroot(v,0);slove(root);
    }
}
int main(){
    n=read();
    for(int i=1;i<n;i++){
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);add(y,x,z);
    }
    k=read();
    f[0]=(1<<30);tmp=n;
    getroot(1,0);
    slove(root);
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/wangxiaodai/p/9767926.html

时间: 2024-08-24 18:14:13

点分治【bzoj1468】 Tree的相关文章

【点分治】bzoj1468 Tree

同poj1741. 换了个更快的姿势,不会重复统计然后再减掉什么的啦~ #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define MAXN 40001 #define INF 2147483647 typedef pair<int,int> Point; int n,K,ans; int v[MAXN<<1],w[MAXN<<

[BZOJ1468]Tree

试题描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入 N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k 输出 一行,有多少对点之间的距离小于等于k 输入示例 7 1 6 13 6 3 9 3 5 7 4 1 3 2 4 20 4 7 2 10 输出示例 5 数据规模及约定 见“输入” 题解 又来一道裸点分治,分别统计重心下面每一颗子树的路径长度和整棵树的路径长度,二分一下算方案数,去重. #include <iostre

【我还不会的】

数位DP.轮廓线DP CDQ分治 博弈论 组合计数 动态点分治 top tree 爬山.退火.蚁群 有上下界网络流 可持久化的各种数据结构 NTT 生成函数 SAM 带花树 link cut cactus 置换群

复习啦。。

模板复习计划.图论:最短路:Dijkstra SPFA Floyed最小圈(*) 二维Dijkstra.SPFA倍增Floyed(*)最小生成树,各种生成树(里面有些还不会) 最小树形图二分图:各种概念,二分图最大权匹配(KM), HC算法(*)网络流:(把所有建模都看一遍,,,不管会不会的)费用流(最小/大费用最大流) ZKW费用流(*)最大流上下界网络流 动态规划:树型Dp(*).数位Dp决策单调性(*)插头DP斯坦纳树(*)记忆化搜索 字符串:后缀自动机.AC自动机.回文自动机,字符串 +

【BZOJ-1468】Tree 树分治

1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k Sample Input 7 1 6 13 6

【BZOJ1468】Tree [点分治]

Tree Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离,问有多少对点它们两者间的距离小于等于K. Input 第一行一个n,接下来n-1行边描述管道,按照题目中写的输入,接下来是一个k. Output 仅包括一个整数,表示有多少对点之间的距离小于等于k. Sample Input 7 1 6 13 6 3 9 3 5 7 4 1 3 2 4 20 4

[bzoj1468][poj1741]Tree[点分治]

可以说是点分治第一题,之前那道的点分治只是模模糊糊,做完这道题感觉清楚了很多,点分治可以理解为每次树的重心(这样会把数分为若干棵子树,子树大小为log级别),然后统计包含重心的整个子树的值减去各个子树的值,这样算出的就是与这个重心有关的情况的答案,比如这道题,求路径,那么就考虑在重心所在的子树中所有的路径减去不过重心的路径就是过重心的路径了.之前重心没找对...poj时间卡的紧就T了.. 1 #include <iostream> 2 #include <algorithm> 3

[bzoj1468][poj1741]Tree_点分治

Tree bzoj-1468 poj-1741 题目大意:给你一颗n个点的树,求树上所有路径边权和不大于m的路径条数. 注释:$1\le n\le 4\cdot 10^4$,$1\le m \le 10^9$. 想法:GXZlegend给高一将点分治,去听了之后的第一道模板题. 我们对于一类树上统计问题,除了强大的树形dp之外,我们还有分治.今天听的是点分治: 就是说,我们将所有的链关于一个点分划成两类:过这个点的链,和不过这个点的链.这个点就是根节点,我在任意两颗子树中拎出两个点,他们之间的链

poj 1744 tree 树分治

Tree Time Limit: 1000MS   Memory Limit: 30000K       Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of ve