【点分治】【路径小于等于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个整数,表示数组的元素,整数之间以一个空格分开.每 ...
随机推荐
- Vue修改mint-ui默认样式(默认风格)
加入my-mint.css 我这里用的postcss的变量定义,如果亲们用的是其他预处理器,要改成其他处理器的定义方式 覆盖mint-ui的primary颜色,改为自己UI的主题色 --main-co ...
- JS 判断手机操作系统代码
还是利用UA, 返回值: ios, android, unknown function getMobileType () { var ua = window.navigator.userAgent.t ...
- logging模块配置笔记
logging模块配置笔记 log文件的路径 #判断在当前的目录下是否有一个logs文件夹.没有则创建 log_dir = os.path.dirname(os.path.dirname(__file ...
- 在html页面中引入公共的头部和底部
参考链接: http://www.cnblogs.com/jason-star/p/3345225.html http://blog.csdn.net/jsxzzliang/article/detai ...
- POJ 2513 Colored Sticks(Tire+欧拉回(通)路判断)
题目链接:http://poj.org/problem?id=2513 题目大意:你有好多根棍子,这些棍子的两端分都别涂了一种颜色.请问你手中的这些棍子能否互相拼接,从而形成一条直线呢? 两根棍子只有 ...
- HDU 2647 Reward(拓扑排序+判断环+分层)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2647 题目大意:要给n个人发工资,告诉你m个关系,给出m行每行a b,表示b的工资小于a的工资,最低工 ...
- jmeter-----GUI运行和非GUI运行的区别
gui:界面会消耗很多资源,并且运行的结果是保存在Jmeter运行的内存中.当时间一长,内存增长到一定程度,就会报错,甚至假死. 非gui:实时的将运行log文件保存到本地文件中,不会撑爆内存.并且对 ...
- 实现优先级队列 --heapq模块
以给定的优先级对元素进行排序,每次pop删除优先级最高的 # coding=utf-8 # example.py # # Example of a priority queue import heap ...
- SQLyog-12.0.9-0.x64
SQLyog-12.0.9-0.x64 下载地址 链接:https://pan.baidu.com/s/1AjC2rdx8Bgtns1sYmN5NEw 提取码:icko 注册码: 姓名(Name):c ...
- HDU 4085 Peach Blossom Spring
斯坦纳树. 最后可以是森林,在计算出每个联通状态的最小费用后,还需要进行一次$dp$. #include<bits/stdc++.h> using namespace std; const ...