【点分治】【路径小于等于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个整数,表示数组的元素,整数之间以一个空格分开.每 ...
随机推荐
- scrapy爬虫框架介绍
一 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前Scrapy的用途十分广泛,可 ...
- sqlite3使用简介
sqlite3使用简介 一.使用流程 要使用sqlite,需要从sqlite官网下载到三个文件,分别为sqlite3.lib,sqlite3.dll,sqlite3.h,然后再在自己的工程中配置好头文 ...
- Tomcat参数调优包括日志、线程数、内存【转】
[Tomcat中日志打印对性能测试的影响] 一般都提供了这样5个日志级别: ▪ Debug ▪ Info ▪ Warn ▪ Error ▪ Fatal 由于性能测试需要并发进行压力测试,如果日志级别是 ...
- int(long) 类型转换为char
char类型占一个字节,8位 int类型四个字节32位 (long类型的转换跟int类型相同) #include <stdio.h> ]) { buffer[] = (char)tmp; ...
- CentOS 7.1使用yum安装MySql5.6.24
http://www.cnblogs.com/yuanfeiblog/p/5276492.html
- scrapy爬虫
a. 配置文件 #settings.py DEPTH_LIMIT = 1 #指定“递归”的层数 ROBOTSTXT_OBEY = False #对方网站规定哪些网址可以爬,这个选项表示不遵循此规定 b ...
- 用 Python实现一个ftp+CRT(不用ftplib)
转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5590004.html 本来最初的想法是实现一个ftp服务器,用来实现用户的登陆注册和文件的断点上传下载等,结果做着 ...
- http学习笔记1
通讯的条件 学前小故事 通过这个故事,我们来理解两台电脑之间的通信,必须具备什么样的条件? 有一天啊,这个小明和小强,一个在山的这头放牛,一个在山的那头割草.但是,由于无聊,这个小明就像找对面的小强聊 ...
- eclipse 创建 maven 项目时如何修改 web 的版本和 jdk 的版本
eclipse 创建 maven 项目时如何修改 web 的版本和 jdk 的版本 在使用 eclipse 创建 maven 项目的时候,默认的 web.xml 的版本时 2.3,默认 jre 的版本 ...
- ES6 简介
1.全称: ECMA 标准,又称ES2015 JavaScript 是大家所了解的语言名称,但是这个语言名称是商标( Oracle 公司注册的商标).因此,JavaScript 的正式名称是 ECMA ...