【点分治】【路径小于等于k的条数】【路径恰好等于k是否存在】
POJ1741:Tree
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 vertices is called valid if and only if dist(u,v) not exceed k. Write a program that will count how many pairs which are valid for a given tree. Input The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros. Output For each test case output the answer on a single line.
Sample Input 5 4 Sample Output 8 Source |
求树上路径距离小于等于k的条数。
点分治即是将树拆开,dfs处理每棵子树的过程。每次找到当前子树的重心,从重心开始分治(即是放弃父亲,不再管之前的祖先。
这道题可以用容斥计算贡献。先统计出当前整棵树的答案,减去每棵子树重复计算的不成立的答案。【注意】这里的答案都是指经过当前树的根节点的路径。
如图,如果k是4,,直接统计子树1的答案,会把1到3和1到4这条路径统计进去,而这是不成立的,所以在统计子树2多余答案时,先把1到2这条边权加进2的dis,再统计子树2中满足条件的点对,减去即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std; int bal, asize, sum, n, k, ans; int tov[], nex[], h[], stot, w[]; void add ( int u, int v, int s ) {
tov[++stot] = v;
w[stot] = s;
nex[stot] = h[u];
h[u] = stot;
} int siz[], vis[]; void find_root ( int u, int f ) {
siz[u] = ;
int res = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == f || vis[v] ) continue;
find_root ( v, u );
siz[u] += siz[v];
res = max ( res, siz[v] );
}
res = max ( res, sum - siz[u] );
if ( res < asize ) {
asize = res, bal = u;
}
} int dep[], dis[]; void get_dep ( int u, int f ) {
dep[++dep[]] = dis[u];
siz[u] = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == f || vis[v] ) continue;
dis[v] = dis[u] + w[i];
get_dep ( v, u );
siz[u] += siz[v];
}
} int cal ( int u, int now ) {
dis[u] = now; dep[] = ;
get_dep ( u, );
sort ( dep + , dep + dep[] + );
int tmp = , l = , r = dep[];
while ( l < r ) {
if ( dep[l] + dep[r] <= k ) {
tmp += r - l; l ++;
} else r --;
}
return tmp;
} void work ( int u ) {
ans += cal ( u, );
vis[u] = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( vis[v] ) continue;
ans -= cal ( v, w[i] );
sum = siz[v];
asize = 0x3f3f3f3f;
find_root ( v, u );
work ( bal );
}
} int main ( ) {
while ( scanf ( "%d%d", &n, &k ) == ) {
if ( n == && k == ) break;
asize = 0x3f3f3f3f;
stot = ; ans = ;
memset ( h, , sizeof ( h ) );
memset ( dis, , sizeof ( dis ) );
memset ( vis, , sizeof ( vis ) );
for ( int i = ; i < n; i ++ ) {
int a, b, c;
scanf ( "%d%d%d", &a, &b, &c );
add ( a, b, c );
add ( b, a, c );
}
sum = n;
find_root ( , );
work ( bal );
printf ( "%d\n", ans );
}
return ;
}
洛谷P3806: 【模板】点分治1
题目背景
感谢hzwer的点分治互测。
题目描述
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
输入输出格式
输入格式:
n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径
接下来m行每行询问一个K
输出格式:
对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)
输入输出样例
说明
对于30%的数据n<=100
对于60%的数据n<=1000,m<=50
对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000
这道题和上一道实质一样,不过我换了种写法。在统计当前树答案时,进入每棵子树,先把这棵子树的答案与之前计算过的子树答案(exist)进行比对,如果可以就更新答案,再更新exist数组,这样可以保证不会出现上面图示情况,因为计算当前子树时,不会出现子树内部互相更新的情况。
#include<iostream>
#include<cstdio>
using namespace std; int n, m, qus[]; int stot, tov[], nex[], h[], w[];
void add ( int u, int v, int s ) {
tov[++stot] = v;
w[stot] = s;
nex[stot] = h[u];
h[u] = stot;
} int siz[], asize, size, root, vis[], maxp[];
void findroot ( int u, int f ) {
siz[u] = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == f || vis[v] ) continue;
findroot ( v, u );
siz[u] += siz[v];
maxp[u] = max ( maxp[u], siz[v] );
}
maxp[u] = max ( maxp[u], size - siz[u] );
if ( maxp[u] < maxp[root] ) root = u;
} int dep[], dis[];
void getdis ( int u, int f ) {
dep[++dep[]] = dis[u];
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == f || vis[v] ) continue;
dis[v] = dis[u] + w[i];
getdis ( v, u );
}
} bool judge[], exist[];
int q[], p;
void count ( int u ) {
int p = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( vis[v] ) continue; dep[] = ; dis[v] = w[i];
getdis ( v, u ); for ( int j = dep[]; j; j -- )
for ( int k = ; k <= m; k ++ )
if ( qus[k] >= dep[j] )
judge[k] |= exist[qus[k]-dep[j]]; for ( int j = dep[]; j; j -- )
q[++p] = dep[j], exist[dep[j]] = ;
}
for ( int i = ; i <= p; i ++ )
exist[q[i]] = ;
} void work ( int u ) {
vis[u] = ; exist[] = ;
count ( u );
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( vis[v] ) continue;
size = siz[v]; root = ;
findroot ( v, );
work ( root );
}
} int main ( ) {
freopen ( "a.in", "r", stdin );
freopen ( "a.out", "w", stdout );
scanf ( "%d%d", &n, &m );
for ( int i = ; i < n; i ++ ) {
int a, b, c;
scanf ( "%d%d%d", &a, &b, &c );
add ( a, b, c );
add ( b, a, c );
} for ( int i = ; i <= m; i ++ )
scanf ( "%d", &qus[i] ); size = n; maxp[root] = n;
findroot ( , );
work ( root ); for ( int i = ; i <= m; i ++ )
if ( judge[i] )
printf ( "AYE\n" );
else printf ( "NAY\n" );
return ;
}
【点分治】【路径小于等于k的条数】【路径恰好等于k是否存在】的更多相关文章
- 【分治】输出前k大的数
描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入第一行包含一个整数n,表示数组的大小.n < 100000.第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整 ...
- OpenJ_Bailian 7617 输出前k大的数
题目传送门 OpenJ_Bailian 7617 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000.第二行包含n个 ...
- 基于快速排序思想partition查找第K大的数或者第K小的数。
快速排序 下面是之前实现过的快速排序的代码. function quickSort(a,left,right){ if(left==right)return; let key=partition(a, ...
- 7617:输出前k大的数
7617:输出前k大的数 查看 提交 统计 提问 总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 给定一个数组,统计前k大的数并且把这k个数从大到小 ...
- 输出前 k 大的数
总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小 ...
- 求数列中第K大的数
原创 利用到快速排序的思想,快速排序思想:https://www.cnblogs.com/chiweiming/p/9188984.html array代表存放数列的数组,K代表第K大的数,mid代表 ...
- 每天一道算法题(32)——输出数组中第k小的数
1.题目 快速输出第K小的数 2.思路 使用快速排序的思想,递归求解.若键值位置i与k相等,返回.若大于k,则在[start,i-1]中寻找第k大的数.若小于k.则在[i+1,end]中寻找第k+st ...
- 输出前k大的数
总时间限制: 10000ms单个测试点时间限制:1000ms内存限制:65536kB(noi) 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大 ...
- noi 统计前k大的数
描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000. 第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每 ...
随机推荐
- H5小游戏——看你有多色
使用了封装了canvas的create.js库来实现的. 最终效果: 工程: Rect.js /* * 方块类 */ function Rect(n,color,specialColor){ crea ...
- okhttp3使用详解
http://blog.csdn.net/itachi85/article/details/51190687
- 使用showplan.sql分析sql Performance
在HelloDBA网站找到一个分析sql性能的工具-showplan,记录一下 showplan.sql下载路径:http://www.HelloDBA.com/Download/showplan.z ...
- ConcurrentHashMap分析
1.ConcurrentHashMap锁分段技术 ConcurrentHashMap使用锁分段技术,首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一 ...
- CSS3 object-fit 图像裁剪
MDN定义 https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-fit 该 object-fit CSS 属性指定替换元素的内容应该如何适应 ...
- linux自动获得mac地址,修改网络配置
1.修改网络配置,自动获得mac地址 删除 /etc/udev/rules.d/70-persistent-net.rules 文件 删除 /etc/sysconfig/network-scripts ...
- C++构造函数详解(复制构造函数)
构造函数是干什么的 该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员. 构造函数的种类 class Compl ...
- APS高级计划排程系统应该支持的企业应用场景
APS高级计划排程系统应该支持的企业应用场景 面对工业4.0智能制造的挑战,很多企业希望能够引进APS高级计划排程系统,全自动的.快速的制定精细化的生产计划,准确的计算产线/设备上各种产品型号的加工顺 ...
- LoadRunner中InvokeMethod failure: 外部组件发生异常解决办法
-82801 abnormal termination,caused by mdrv process termination -29996 error:process mmdrv.exe was no ...
- 微软企业库5.0 学习之路——扩展学习篇、库中的依赖关系注入(重构 Microsoft Enterprise Library)[转]
这篇文章是我在patterns & practices看到的一篇有关EntLib5.0的文章,主要介绍了EntLib5.0的这次的架构变化由来,觉得很不错,大家可以看一下! 在过去几年中,依赖 ...