POJ-1741(树分治)
树的点分治
给出详细的讲解!!点这里打开论文-分治算法在树的路径问题中的应用

本题目是他讲的第一个例题;
我的理解:每次都找树的重心,计算以重心为根的子树之间所贡献的答案。不断这样下去;如果这棵树是一条链,那么就和快排,归并的线性分治法一样了。如果不是一条链那么就相当于,选中一个点,标记为使用过。然后树会被这个节点划分成多棵子树。然后这样分治下去。思想好理解。但是代码不是很好想!详见注解。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long int LL;
const int maxn=20000+100;
struct Node
{
    int to,val,next;
}edge[maxn];
int first[maxn],sz,ans,idx,root,n,k;
bool vis[maxn];
/* ----------------------*/
/**
 * 邻接表部分
 */
void init()
{
    memset(first,-1,sizeof(first));
    memset(vis,0,sizeof(vis));
    sz=0;
}
void addedge(int s,int t,int val)
{
    edge[sz].val=val,edge[sz].to=t,edge[sz].next=first[s];
    first[s]=sz++;
}
/*****
 * mi,用来找树的重心的时候作比较用的;
 * mx[i]数组 代表i节点的子树中最大的size;
 * size[i]代表i节点的子树的节点数量;
 * dis[i]代表i好节点到根的深度;
 * ****************************/
int mi,mx[maxn],size[maxn],dis[maxn];
void dfssize(int x,int pre)  //x节点这个子树求size,mx;
{
    size[x]=1;
    mx[x]=0;
    for(int i=first[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to,val=edge[i].val;
        if(to!=pre&&!vis[to])
        {
            dfssize(to,x);
            size[x]+=size[to];
            if(size[to]>mx[x]) mx[x]=size[to];
        }
    }
}
void dfsroot(int rt,int x,int pre) //找rt这个 子树的重心
{
    mx[x]=max(mx[x],size[rt]-size[x]);
    if(mx[x]<mi) mi=mx[x],root=x;
    for(int i=first[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to!=pre&&!vis[to]) dfsroot(rt,to,x);
    }
}
void dfsdis(int x,int pre,int dd) //计算子树 x的 dis 数组;
{
    dis[idx++]=dd;
    for(int i=first[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to,val=edge[i].val;
        if(to!=pre&&!vis[to]) dfsdis(to,x,dd+val);
    }
}
/**
 * 计算 F(x)=(子树x的 depth(i)+depth(j)<=k 的对数;)
 * calc(x,d);当d=0;返回的是x这颗子树F(x),
 * 等d=某条边权值,calc(x,d) 返回值代表子树之间的F(x)
*/
int calc(int x,int d)
{
    int res=0;
    idx=0;
    dfsdis(x,x,d);
    sort(dis,dis+idx);
    int i=0,j=idx-1;
    while(i<j)
    {
        while(dis[i]+dis[j]>k&&i<j) j--;
        res+=j-i;
        i++;
    }
    return res;
}
void dfs(int x)
{
    mi=n;
    dfssize(x,x);
    dfsroot(x,x,x);
    ans+=calc(root,0);//当前节点
    vis[root]=1;
    for(int i=first[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to,val=edge[i].val;
        if(!vis[to])
        {
            ans-=calc(to,val);//减去当前节点的子树之间的
//            printf(">> calc=%d\n",calc(root,val));
            dfs(to);
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(n==0&&k==0) break;
        init();
        for(int i=1;i<n;i++)
        {
            int x,y,val;
            scanf("%d%d%d",&x,&y,&val);
            addedge(x,y,val);
            addedge(y,x,val);
        }
        ans=0;
        dfs(1);
        printf("%d\n",ans);
    }
    return 0;
}
POJ-1741(树分治)的更多相关文章
- POJ 1741 树分治
		题目链接[http://poj.org/problem?id=1741] 题意: 给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数. 题解: 这是一个很经典 ... 
- poj 1741 树的点分治(入门)
		Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 18205 Accepted: 5951 Description ... 
- poj 1741 树的分治
		思路:这题我是看 漆子超<分治算法在树的路径问题中的应用>写的. 附代码: #include<iostream> #include<cstring> #includ ... 
- POJ 1741 树的点分治
		题目大意: 树上找到有多少条路径的边权值和>=k 这里在树上进行点分治,需要找到重心保证自己的不会出现过于长的链来降低复杂度 #include <cstdio> #include & ... 
- POJ 1741 [点分治][树上路径问题]
		/* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给一棵有n个节点的树,每条边都有一个正权值,求一共有多少个点对使得它们之间路的权值和小于给定的k. 思路: <分治算法在树的路径问题中的应用 ... 
- [八分之三的男人] POJ - 1741 点分治 && 点分治笔记
		题意:给出一棵带边权树,询问有多少点对的距离小于等于\(k\) 本题解参考lyd的算法竞赛进阶指南,讲解的十分清晰,比网上那些讲的乱七八糟的好多了 不过写起来还是困难重重(史诗巨作 打完多校更详细做法 ... 
- POJ 1741 点分治
		方法:指针扫描数组 每次选择树的重心作为树根,从树根出发进行一次DFS,求出点到树根的距离,把节点按照与树根的的距离放进数组d,设置两个指针L,R分别从前.后开始扫描,每次满足条件时答案累加R-L., ... 
- POJ 1741.Tree 树分治 树形dp 树上点对
		Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ... 
- poj 1741 Tree(树的点分治)
		poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ... 
- POJ 1741 Tree【树分治】
		第一次接触树分治,看了论文又照挑战上抄的代码,也就理解到这个层次了.. 以后做题中再慢慢体会学习. 题目链接: http://poj.org/problem?id=1741 题意: 给定树和树边的权重 ... 
随机推荐
- CG标准函数库——数学函数(GPU编程与CG语言之阳春白雪下里巴人)
- Mysql字符串截取函数
			今天建视图时,用到了MySQL中的字符串截取,很是方便. 感觉上MySQL的字符串函数截取字符,比用程序截取(如PHP或JAVA)来得强大,所以在这里做一个记录,希望对大家有用. 函数: 1.从左开始 ... 
- jQuery.callbacks 注释
			(function( jQuery ) { // String to Object flags format cache var flagsCache = {}; // Convert String- ... 
- POJ 2965 The Pilots Brothers' refrigerator【枚举+dfs】
			题目:http://poj.org/problem?id=2965 来源:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26732#pro ... 
- ORDER BY today_used ASC' % (MAX_USED_TIMES)
			python D:\pymine\clean\spider_map\get_bd_uid_rest_b.py python D:\pymine\clean\spider_map\get_bd_uid_ ... 
- vue 计算属性和监听器
			一.计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护.例如: <div> {{ message.split('').rev ... 
- ubuntun下安装Fiddler
			对于分析网页或者写爬虫的时候经常需要用到抓包工具进行网页数据的抓包.在Windows下可以安装Fiddler来抓包.在ubuntun下不能直接安装Fiddler.需要先安装mono 1 首先安装mon ... 
- 丢失vcruntime140.dll
			我在php7安装yaf时报了标题所提示的错误信息. 解决方案是:下载vc++2015 并安装 链接如下:https://www.microsoft.com/zh-cn/download/confirm ... 
- ABAP动态生成经典应用之Dynamic SQL Excute 程序
			[转自http://blog.csdn.net/mysingle/article/details/678598]开发说明:在SAP的系统维护过程中,有时我们需要修改一些Table中的数据,可是很多Ta ... 
- dig指定服务器查询域名解析时间
			time=$(dig @8.8.8.8 baidu.com | grep Query | awk '{print $4}') echo $time 一 nslookup指定服务器查询域名解析时间 ro ... 
