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 题意: 给定树和树边的权重 ...
随机推荐
- JWT简介json web token bear token
, "exp": 1502360328,(相差3600s) "nbf": , "jti": "R0Gd00AvOW259LGo&q ...
- 模拟多级复选框效果--jquery
今天又次体会到jquery的强大了,做了个多级复选框的效果,代码总共就20+行就over了. 我又想用js来做一个看看,才写了几个方法就写不动了,兼容性要考虑很多,而且代码量直线上升. 主要分享下jq ...
- 【Unity 3D】学习笔记四十二:粒子特效
粒子特效 粒子特效的原理是将若干粒子无规则的组合在一起.来模拟火焰,爆炸.水滴,雾气等效果. 要使用粒子特效首先要创建,在hierarchy视图中点击create--particle system就可 ...
- 如何创建AnjularJS项目
第一步:命名空间 var applyAppModule=angular.module('apply-app' ,[]); 第二步:控制器 ng-controller="ApplyCon ...
- java解析字符串拆分单独元素
有时候,需求要求传递多个字符串参数,但是方法参数已经固定为单个String,笔者在学习unity和android之间的消息传递时就遇到这个问题,所以就写了这么一个解析字符串拆分单独元素的方法. 示例: ...
- 由浅到深理解ROS(1)
ROS机器人操作系统 ( Robot Operating System 或简称 ROS),可以帮助提高机器人软件的开发效率.ROS能够提供类似传统操作系统的诸多功能,如硬件抽象.底层设备控制.常用功能 ...
- Android 热门技术干货
http://mp.weixin.qq.com/s?__biz=MzIwMzYwMTk1NA==&mid=2247484939&idx=1&sn=d1871b09de55ca6 ...
- yii2.0 console执行php守护进程
//该方法只需执行一次public function actionIndex(){ $pid =pcntl_fork();//在当前进程中生成一个新的子进程 //$pid会有三种形式 $pid==-1 ...
- A/B(逆元)
A/B Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- Leftmost Digit(hdu1060)(数学题)
Leftmost Digit Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...