POJ 1741 Tree(经典点分)题解
来源:互联网 发布:qq软件管家最新版 编辑:程序博客网 时间:2024/05/28 15:36
青少年是一个美好而又是一去不可再得的时期,是将来一切光明和幸福的开端。——加里宁
这道题是经典的点分,拿来练练手。
题目大意:
一行n,m范围是100000。(n是树的节点树木,m是树上链长度上限)
下面n-1行每行三个数给定树,(前两个给定树的边,后一个为长度)。
注意:是多组数据,最后两个0 0结束。
然后询问树上不超过m的链的个数。
Example:
IN PUT:
5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0
OUT PUT:
8
具体实现:
我们每次进行点分(求重心),然后对链进行处理,咋处理呢。
因为一条链必定在重心的两颗不同的子树内(易证得),所以大体思想是求出所有点到重心的距离,然后求出所有满足不大于m的链的个数,最后减去一个子树内的个数。
详见代码:
//// main.cpp// POJ 1741//// Created by apple on 17/3/20.// Copyright © 2017年 apple. All rights reserved.//#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 100005;struct Edge{ int v, next, w;};Edge e[2 * N];int n, m, head[N], num, x, y, z, vis[N], siz[N], f[N], sum, root, dis[N], tot, ans;void adde( int i, int j, int w ) { e[++num].v = j; e[num].next = head[i]; e[num].w = w; head[i] = num;}void init() {//初始化 memset( head, 0, sizeof(head) ); memset( vis, 0, sizeof(vis) ); for ( int i = 1; i < n; i++ ) { scanf( "%d%d%d", &x, &y, &z ); adde( x, y, z ); adde( y, x, z ); }}void getroot( int u, int fa ) {//求树的重心 siz[u] = 1; f[u] = 0; for ( int i = head[u]; i; i = e[i].next ) { int v = e[i].v; if ( v == fa || vis[v] ) continue; getroot(v, u); siz[u] += siz[v]; f[u] = max( f[u], siz[v] ); } f[u] = max(f[u], sum-siz[u]); if ( f[u] < f[root] ) root = u;}void getdis( int u, int d, int fa ) {//求点到重心的距离 dis[++tot] = d; for ( int i = head[u]; i; i = e[i].next ) { int v = e[i].v; if ( v == fa || vis[v] ) continue; getdis(v, d+e[i].w, u); }}int calc( int u, int d ) {//计算满足要求的个数 int ret = 0; tot = 0; getdis(u, d, 0); sort(dis+1, dis+tot+1); int i = 1, j = tot; while ( i < j ) {//经典的双向 if ( dis[i] + dis[j] <= m && i < j ) { ret += ( j - i ); i++; } else j--; } return ret;}void solv( int u ) { ans += calc( u, 0 );//加上所有满足要求 vis[u] = 1; for ( int i = head[u]; i; i = e[i].next ) { int v = e[i].v; if ( vis[v] ) continue; ans -= calc(v, e[i].w);//减去在同一个子树内的个数 sum = siz[v];//求重心的初始化 root = 0; getroot(v, 0); solv(root);//递归解决 }}int main() { while (1) { ans = 0; scanf("%d%d", &n, &m); if ( n == 0 && m == 0 ) break; init(); sum = n; root = 0; f[0] = 0x3f3f3f3f; getroot(1, 0); solv(root); printf( "%d\n", ans ); } return 0;}
完毕!
附上我对你的思念。
0 0
- POJ 1741 Tree(经典点分)题解
- POJ 1741 Tree(点分治)
- POJ 1741 Tree(树+点分治)
- 【POJ 1741】Tree (树上点分治)
- [POJ 1741] Tree (点分治)
- POJ-1741-Tree (点分治)
- POJ 1741 Tree (点分治)
- poj 1741 Tree 点分治
- 【POJ 1741】 Tree --点分治
- 【POJ】1741 Tree 点分治
- 【POJ】1741 Tree 点分治
- poj 1741 Tree 点分治
- POJ 1741 Tree 点分治
- poj 1741 Tree 点分治
- POJ 1741 Tree 点分治
- poj 1741Tree(点分治)
- 点分治 POJ 1741 Tree
- POJ 1741 Tree 点分治
- Problem E: C语言习题 学生成绩输入和输出
- JQuery中的事件 (五.事件对象的属性)
- c++第三次实验-多分数段函数求值
- Vue.2.0-Class 与 Style 绑定
- vmware下ubuntu于windows共享文件夹
- POJ 1741 Tree(经典点分)题解
- SVDD(Support Vector Domain Description) 支持向量数据域描述(2)
- MySql 设置表名不区分大小写
- 为什么选择zigbee?
- java设计模式复习——23中设计模式
- jQuery提示插件alertify使用指南
- 1 关于逆向工程
- 二次排序的实现代码
- [Sublime Text 3 usage]: Emmet 和 EmmetOneLine 使用