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 题意: 给定树和树边的权重 ...
随机推荐
- cordova ios升级插件
org.ssgroup.sope.cordova.upgrade 支持强制升级与选择升级 插件已经开源在https://github.com/shenshouer/org.ssgroup.sope.c ...
- 走进Struts2(五)— 值栈和OGNL
值栈 1.值栈是什么? 简单说:就是相应每个请求对象的轻量级的内存数据中心. Struts2引入值栈最大的优点就是:在大多数情况下,用户根本无须关心值栈,无论它在哪里,不用管它里面有什么,仅仅须要去获 ...
- LCD驱动程序(一)
LCD显示原理: 在JZ2440上,想要让LCD显示,需要几个部分1.LCD硬件 2.开发板上的LCD控制器 3.SDRAM内存存放数据FramBuffer 4.可能还需要一个调色板(实际上是一块内存 ...
- iphone怎么检测屏幕是否被点亮 (用UIApplication的Delegate)
本文转载至 http://gaohaijun.blog.163.com/blog/static/176698271201161524857373/ 问题:那位能说一下怎么能检测到iphone ...
- sql server 2008 去除html标签
由于商品详情数据库的字段是text,存放的是html,但是要求导出的商品详情中只是商品的描述,不要标签,原来打算先把数据导入excel中,然后利用java的正则去替换,结果由于商品详情太大,一个单元格 ...
- 【BZOJ3707】圈地 几何
[BZOJ3707]圈地 Description 2维平面上有n个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小.圈地需要圈一个至少3个点的多边形,多 ...
- 【BZOJ3991】[SDOI2015]寻宝游戏 树链的并+set
[BZOJ3991][SDOI2015]寻宝游戏 Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩 ...
- 九度OJ 1339:ACM (排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:712 解决:379 题目描述: 今年的ACM世界总决赛快要开始了,需要有一个排名算法来对每支队伍进行现场排名.ACM组委会把这个任务交给了你 ...
- vue介绍和简单使用
Vue是什么? Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易 ...
- 第一个Spring Boot程序启动报错了
创建完成第一个Spring Boot项目后,准备运行,尝一下胜利的果实. 启动日志如下 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ...