Description

眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游。
Crash和陶陶所要去的城市里有N (N > 1) 个景点,Crash用正整数1到N给景点标号。
这些景点之间通过N - 1条无向道路相连,每条道路有一个长度,并且保证任意两个景点之间都有且仅有一条路径相连。
现在对于一个景点s,Crash和陶陶从s出发,然后访问一个景点序列{v0, v1, v2, … , vk},
其中v0就是s,且vi-1和vi(0 < i ≤ k)之间有道路相连。
需要注意的是,陶陶和Crash访问的景点序列中不会只有景点s。
为了使旅程不显得乏味,在一个景点序列里他们不会重复走某条道路。
我们定义这个序列的旅游代价为经过道路的长度和。下面问题出现了:
陶陶:我们走一条景点数最多的景点序列吧。
Crash:倒,你想把我累死啊。
陶陶:谁叫你整天坐在电脑前面,不出来锻炼,这下子傻了吧,哈哈哈哈~~
Crash:不行,如果你非要走景点数最多的我就不陪你走了。
陶陶:笑喷油你很跳嘛!
Crash:这样吧,我们来写伸展树,如果我写的比你快,你就要听我的。
陶陶:这样不公平哎,我们来玩PES吧,当然你要让我选法国队,如果你输了你就要听我的。
Crash:倒,你这是欺负我,T_T~
陶陶:笑喷油好说话哎。
Crash:囧……
……
这样搞了半天,最终陶陶和Crash用很多次包剪锤决定出选择旅游代价第K小 的景点序列。
不过呢Crash和陶陶还没确定开始旅行的景点s,因此他希望你对于每个景点i,计算从景点i开始的景点序列中旅游代价第K小的值。

Input

共N行。
第1行包含一个字符和两个正整数,字符为ABCD中的一个,用来表示这个测试数据的类型
(详见下面的数据规模和约定),另外两个正整数分别表示N和K (K < N),N<=100000
第2行至第N行,每行有三个正整数u、v和w (u, v ≤ N,w ≤ 10000)。
表示u号景点和v号景点之间有一条道路,长度为w。
输入文件保证符合题目的约定,即任意两个景点之间都有且仅有一条路径相连。

Output

共N行,每行有一个正整数。
第i行的正整数表示从i号景点开始的景点序列中旅游代价第K小的代价。

Sample Input

A 6 3

1 2 2

1 3 4

1 4 3

3 5 1

3 6 2

Sample Output

4

6

4

7

5

6

//样例1中输出对应的景点序列分别为:

1号景点是{1, 3},2号景点是{2, 1, 3},3号景点是{3, 1},4号景点是{4, 1, 3},5号景点是{5, 3, 1},6号景点是{6, 3, 1}。

保证每个景点到1号景点需要经过的道路数不超过30


题解

题意就是给出\(n\)个点的一棵树,对于每个点求出距离ta第\(k\)小的距离

动态点分治
我们可以先建出点分树
然后二分一个距离\(k\),判断其他点到这个点的距离小于等于这个值的有几个
那么现在的问题就是给出一个点,求出到这个点的距离不大于\(k\)的有几个点
记\(v1[u]\)数组表示\(u\)的子树内的点到\(u\)的距离,\(v2[u]\)表示\(u\)的子树内的点到\(fa[u]\)的距离
然后每次查询点\(u\)的时候就顺着点分树往上跳,期间查询所有的点到点\(u\)的距离不超过\(k\)的点
注意每次往上跳到\(fa[u]\)再查\(fa[u]\)的子树的时候会把已经统计过的\(u\)的子树的信息重复统计一部分,所以我们要容斥掉\(u\)的子树内的信息
注意往上跳的时候如果跳到点\(x\)使得\(dis(u,x)>k\)也不要直接\(break\),而是要继续往上跳,因为点分树是将原树重构了,可能\(dis(u,x)>k\)了但是\(x\)的祖先到\(u\)的距离\(\le k\)

代码

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 200005 ;
const int INF = 1e9 ;
using namespace std ;inline int read() {char c = getchar() ; int x = 0 , w = 1 ;while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }return x*w ;
}bool vis[M] ;
int n , k , num , tot , tmx , root , hea[M] ;
int dis[M] , ff[M] , fa[M] , size[M] , dep[M] , son[M] , top[M] ;
vector < int > v1[M] , v2[M] ;
struct E { int nxt , to , dis ; } edge[M * 2] ;
inline void add_edge(int from , int to , int dis) {edge[++num].nxt = hea[from] ; edge[num].to = to ;edge[num].dis = dis ; hea[from] = num ;
}void dfs1(int u , int father , int depth) {ff[u] = father ; size[u] = 1 ; dep[u] = depth ; int mx = -1 ;for(int i = hea[u] ; i ; i = edge[i].nxt) {int v = edge[i].to ; if(v == father) continue ;dis[v] = dis[u] + edge[i].dis ; dfs1(v , u , depth + 1) ; size[u] += size[v] ;  if(size[v] > mx) mx = size[v] , son[u] = v ;}
}
void dfs2(int u , int topf) {top[u] = topf ; if(!son[u]) return ; dfs2(son[u] , topf) ;for(int i = hea[u] ; i ; i = edge[i].nxt) {int v = edge[i].to ; if(v == ff[u] || v == son[u]) continue ;dfs2(v , v) ;}
}
inline int LCA(int x , int y) {while(top[x] != top[y]) {if(dep[top[x]] < dep[top[y]]) swap(x , y) ;x = ff[top[x]] ;}return dep[x] < dep[y] ? x : y ;
}
inline int Gdis(int x , int y) {return dis[x] + dis[y] - dis[LCA(x , y)] * 2 ;
}
void findroot(int u , int father) {size[u] = 1 ; int mx = 0 ;for(int i = hea[u] ; i ; i = edge[i].nxt) {int v = edge[i].to ; if(vis[v] || v == father) continue ;findroot(v , u) ; mx = max(mx , size[v]) ; size[u] += size[v] ;}mx = max(mx , tot - size[u]) ;if(mx < tmx) tmx = mx , root = u ;
}void Solve(int u , int father) {fa[u] = father ; vis[u] = true ;for(int i = hea[u] ; i ; i = edge[i].nxt) {int v = edge[i].to ; if(vis[v]) continue ;tot = size[v] ; tmx = INF ; findroot(v , u) ; Solve(root , u) ;}
}
// v1 表示u的子树内的点到u的距离
// v2 表示u的子树内的点到fa[u]的距离
inline void Insert(int x) {v1[x].push_back(0) ;for(int u = x ; fa[u] ; u = fa[u]) {v1[fa[u]].push_back(Gdis(x , fa[u])) ;v2[u].push_back(Gdis(x , fa[u])) ;}
}
inline int query(int id , int x , int k) {if(id == 1) {int l = 0 , r = v1[x].size() - 1 , mid , ret = -1 ;while(l <= r) {mid = (l + r) >> 1 ;if(v1[x][mid] <= k) l = mid + 1 , ret = mid ;else r = mid - 1 ;}return ret + 1 ;}else {int l = 0 , r = v2[x].size() - 1 , mid , ret = -1 ;while(l <= r) {mid = (l + r) >> 1 ;if(v2[x][mid] <= k) l = mid + 1 , ret = mid ;else r = mid - 1 ;}return ret + 1 ;}
}
inline int check(int x , int k) {int ans = query(1 , x , k) ;for(int u = x , dis1 ; fa[u] ; u = fa[u]) {dis1 = Gdis(x , fa[u]) ; if(k - dis1 < 0) continue ;ans += query(1 , fa[u] , k - dis1) - query(2 , u , k - dis1) ;}return ans - 1 ;
}
int main() {char s[10] ; scanf("%s",s) ; n = read() ; k = read() ;for(int i = 1 , u , v , w ; i < n ; i ++) {u = read() ; v = read() ; w = read() ;add_edge(u , v , w) ; add_edge(v , u , w) ;}dfs1(1 , 0 , 1) ; dfs2(1 , 1) ; tot = n ; tmx = INF ; findroot(1 , 0) ; Solve(root , 0) ;for(int i = 1 ; i <= n ; i ++) Insert(i) ;for(int i = 1 ; i <= n ; i ++) {sort(v1[i].begin() , v1[i].end()) ;sort(v2[i].begin() , v2[i].end()) ;}for(int u = 1 ; u <= n ; u ++) {int l = 1 , r = 1e9 , ret = 0 ;while(l <= r) {int mid = (l + r) >> 1 ;if(check(u , mid) >= k) ret = mid , r = mid - 1 ;else l = mid + 1 ;}printf("%d\n",ret) ;}return 0 ;
}

转载于:https://www.cnblogs.com/beretty/p/10645671.html

[2010国家集训队]Crash的旅游计划相关推荐

  1. 【BZOJ2117】 [2010国家集训队]Crash的旅游计划

    [BZOJ2117] [2010国家集训队]Crash的旅游计划 Description 眼看着假期就要到了,Crash由于长期切题而感到无聊了,因此他决定利用这个假期和好友陶陶一起出去旅游. Cra ...

  2. BZOJ 2154 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演,经典好题)(Luogu P1829)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 P1829 [国家集训队]Crash的数字表格 / JZPTAB(反演,经典好题) Problem S ...

  3. P1829 [国家集训队]Crash的数字表格(推了好久的mobius反演)

    P1829 [国家集训队]Crash的数字表格 / JZPTAB 推导过程 ∑i=1n∑j=1mlcm(i,j)\sum_{i = 1} ^{n} \sum_{j = 1} ^{m} lcm(i, j ...

  4. P4827 [国家集训队] Crash 的文明世界

    P4827 [国家集训队] Crash 的文明世界 题目描述 Solution 看到这种kkk次幂的式子,就应该往斯特林数的方面想想. mn=∑i{ni}(ni)i!m^n=\sum_i \left\ ...

  5. P1829 [国家集训队]Crash的数字表格 / JZPTAB

    P1829 [国家集训队]Crash的数字表格 / JZPTAB 题意: 求∑i=1n∑j=1mlcm(i,j)\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)∑i=1n​∑j ...

  6. P1829 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

    [国家集训队]Crash的数字表格 / JZPTAB 题目描述 今天的数学课上,Crash 小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数 a a a 和 b b ...

  7. BZOJ 2156 「国家集训队」星际探索(最短路)【BZOJ计划】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2156 是 hydro 的 BZOJ ...

  8. 数据结构(莫队算法):国家集训队2010 小Z的袜子

    [题目描述] 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到 ...

  9. Luogu P2619 [国家集训队2]Tree I(WQS二分+最小生成树)

    P2619 [国家集训队2]Tree I 题意 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有\(need\)条白色边的生成树. 题目保证有解. 输入输出格式 输入格式 ...

最新文章

  1. Map获取键值,Map的几种遍历方法
  2. git fetch和git pull
  3. Python基础教程:赋值语句和布尔值
  4. 在c++中,如果派生类没有重写基类中对应virtual函数会怎样?
  5. 机器学习入门(1)之基本概念简介
  6. 计算机外围设备哪两类,《微机原理与接口技术》课后习题答案
  7. 为什么换工作?(面试必问问题)
  8. Ubuntu Linux环境下的Android开发环境的配置
  9. OpenCV学习(13) 细化算法(1)(转)
  10. PHP期望T_PAAMAYIM_NEKUDOTAYIM?
  11. java中异常的定义_java中异常的理解
  12. 小瓜牛漫谈 — 获取资源文件
  13. 啊哈算法(pdf免积分下载)
  14. 【生活中的逻辑谬误】功利误导和情感误导
  15. WORD文档插入页码时有几页不显示不显示页码?怎么解决
  16. 最近 火火火 的开源项目
  17. C3 linearization
  18. 华为手机主界面的返回键怎么调出来_华为手机没有返回键怎么调出来
  19. Facebook借足球影响力推广直播:与俱乐部和球星合作分成
  20. 国家标准GB7713-87

热门文章

  1. 《C++ Primer 4th》读书笔记 第6章-语句
  2. 计算机中的颜色XIII——颜色转换的快速计算公式
  3. 分享几个可以放在博客里的小工具
  4. Kubernetes初探:原理及实践应用
  5. FFmpeg的添加logo,去logo
  6. 64 bit Ubuntu support 32 bit binary
  7. win 8升级win8.1的几个问题
  8. NOIp #2010
  9. hibernate和jdbc的优缺点,概述
  10. ORACLE MTTR