Description

公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

 

Input

第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n

 

Output

输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

 

Sample Input

6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5

Sample Output

11

Hint

将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。
将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。
将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。
将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。
将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。
故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。

(原题传送门[here])


  首先需要求LCA,把所有询问的求的LCA和出发点,结束点保存下来。

  然后二分答案。判断是否可以把耗时大于它的航线的用时缩短到小于等于二分值。

  这个判定就用差分,先在数组中将LCA的值-2,出发点和结束点的值分别+1,从叶节点向上累加。

  关于判定就找1个所有需要改的航线都覆盖了的边。并且使耗时的最大值要不超过二分值,这样样就行了。否则说明还会有航线的值大于二分值。

  另外注意常数对算法的影响,理论复杂度O(n + m + nlog2L)。(L是树上最长链的长度)

Code

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
#define smin(a, b) a = min(a, b)
#define smax(a, b) a = max(a, b)
typedef bool boolean;
template<typename T>
inline void readInteger(T& u){
char x;
while(!isdigit((x = getchar())));
for(u = x - ''; isdigit((x = getchar())); u = (u << ) + (u << ) + x - '');
ungetc(x, stdin);
} typedef class Edge{
public:
int end;
int next;
int w;
Edge(const int end = , const int next = , const int w = ):end(end), next(next), w(w){}
}Edge; typedef class MapManager{
public:
int ce;
int* h;
Edge* edge;
MapManager(){}
MapManager(int points, int edges):ce(){
h = new int[(const int)(points + )];
edge = new Edge[(const int)(edges + )];
memset(h, , sizeof(int) * (points + ));
}
inline void addEdge(int from, int end, int w){
edge[++ce] = Edge(end, h[from], w);
h[from] = ce;
}
inline void addDoubleEdge(int from, int end, int w){
addEdge(from, end, w);
addEdge(end, from, w);
}
}MapManager; #define m_begin(g, i) (g).h[(i)]
#define m_end(g, i) (g).edge[(i)].end
#define m_next(g, i) (g).edge[(i)].next
#define m_w(g, i) (g).edge[(i)].w template<typename T>class Matrix{
public:
T *p;
int lines;
int rows;
Matrix():p(NULL){ }
Matrix(int lines, int rows):lines(lines), rows(rows){
p = new T[(lines * rows)];
}
T* operator [](int pos){
return (p + pos * lines);
}
};
#define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) typedef class union_found{
public:
int *f;
union_found():f(NULL) {}
union_found(int points) {
f = new int[(const int)(points + )];
}
int find(int x) {
if(f[x] != x) return f[x] = find(f[x]);
return f[x];
}
int& operator [](int pos){
return f[pos];
}
}union_found; #define BZ_MAX 19 typedef class query{
public:
int from;
int end;
int minv;
int lca;
query(const int from = , const int end = , const int lca = , const int minv = ):from(from), lca(lca), end(end), minv(minv){}
boolean operator <(query another) const {
return this->minv < another.minv;
} }query; boolean operator <(int val, query a){
return val < a.minv;
}
int n, q;
int cq;
int* times;
int* up;
int* dis;
MapManager g;
boolean* visited;
boolean* enable;
query *results;
MapManager mq;
union_found uf; inline void init(){
readInteger(n);
readInteger(q);
g = MapManager(n, * n);
mq = MapManager(n, * q);
for(int i = , a, b, c; i < n; i++){
readInteger(a);
readInteger(b);
readInteger(c);
g.addDoubleEdge(a, b, c);
}
for(int i = , a, b; i <= q; i++){
readInteger(a);
readInteger(b);
mq.addDoubleEdge(a, b, );
}
} void dfs(int node, int last, int distance){
up[node] = last;
dis[node] = distance;
for(int i = m_begin(g, node); i != ; i = m_next(g, i)){
int &e = m_end(g, i);
if(e == last) continue;
dfs(e, node, m_w(g, i) + distance);
}
} inline void init_dfs(){
up = new int[(const int)(n + )];
dis = new int[(const int)(n + )];
uf = union_found(n + );
visited = new boolean[(const int)(n + )];
enable = new boolean[(const int)(q * + )];
memset(up, , sizeof(int) * (n + ));
memset(enable, true, sizeof(boolean) * (q * + ));
memset(visited, false, sizeof(boolean) * (n + ));
dfs(, , );
} int cal_length(int a, int b, int lca){
return dis[a] + dis[b] - (dis[lca] << );
} void tarjan(int node){
uf[node] = node;
visited[node] = true;
for(int i = m_begin(g, node); i != ; i = m_next(g, i)){
int& e = m_end(g, i);
if(!visited[e]){
tarjan(e);
uf[e] = node;
}
}
for(int i = m_begin(mq, node); i != ; i = m_next(mq, i)){
int& e = m_end(mq, i);
if(visited[e] && enable[i]){
int lca = uf.find(e);
results[++cq] = query(node, e, lca, cal_length(node, e, lca));
enable[i] = enable[i + ((i & ) ? () : (-))] = false;
}
}
} boolean update(int node, int limit, int maxer, int minx){
for(int j = m_begin(g, node); j != ; j = m_next(g, j)){
int& e = m_end(g, j);
if(e == up[node]) continue;
if(update(e, limit, maxer, minx)) return true;
times[node] += times[e];
}
if(times[node] == limit){
if(maxer - cal_length(node, up[node], up[node]) <= minx){
return true;
}
}
return false;
} boolean check(int minx){
int counter = ;
int maxer = ;
memset(times, , sizeof(int) * (n + ));
query* it = upper_bound(results + , results + q + , minx);
for(; it != results + q + ; it++){
times[it->from]++;
times[it->end]++;
times[it->lca]++;
counter++;
smax(maxer, it->minv);
}
return update(, counter, maxer, minx);
} inline void solve(){
int l = , r;
results = new query[(const int)(q + )];
tarjan();
delete[] visited;
delete[] uf.f;
times = new int[(const int)(n + )];
sort(results + , results + q + );
r = results[q].minv;
while(l <= r){
int mid = l + ((r - l) >> );
if(check(mid)) r = mid - ;
else l = mid + ;
}
printf("%d", r + );
} int main(){
init();
init_dfs();
solve();
return ;
}

(PS:这道题很神奇,vijos过了,codevs的最后一个点TLE)

vijos 运输计划 - 二分答案 - 差分 - Tarjan的更多相关文章

  1. 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)

    P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...

  2. luogu P2680 运输计划 (二分答案+树上差分)

    题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...

  3. [luogu]P2680 运输计划[二分答案][树上差分]

    [luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...

  4. loj2425 「NOIP2015」运输计划[二分答案+树上差分]

    看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...

  5. 运输计划[二分答案 LCA 树上差分]

    也许更好的阅读体验 \(\mathcal{Description}\) 原题链接 概括一下题意 给一颗有\(n\)个点带边权的树,有\(m\)个询问,每次询问\(u,v\)两点间的权值和,你可以将树中 ...

  6. BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1930  Solved: 1231[Submit][Statu ...

  7. 【bzoj4326】[NOIP2015]运输计划 二分答案+LCA

    题目描述 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该 ...

  8. Luogu P2680 运输计划(二分+树上差分)

    P2680 运输计划 题意 题目背景 公元\(2044\)年,人类进入了宇宙纪元. 题目描述 公元\(2044\)年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道 ...

  9. P2680 运输计划 二分+树上差分

    又咕咕了几天\(QwQ\) 思路:二分+树上差分 提交:\(\geq5\)次 错因:\(lca\)写错+卡了很久常数(哪位大佬帮我康康,有更好的写法请指出\(QwQ\)) 题解: 我们先将原问题转化为 ...

随机推荐

  1. 算术平均数 print('arithmeticAverageSingleCompressionRatio:', sum(singleCompressionRatio)/len(singleCompressionRatio))

    print('arithmeticAverageSingleCompressionRatio:', sum(singleCompressionRatio)/len(singleCompressionR ...

  2. Word文档中的格式标记大全

    在Word中有很多的格式设置,很多格式设置都会有一些标记,这些标记是隐藏的,在打印文档时是不会打印出来的,但是它们却起着结构化文档的大作用.如果你在编辑文档,不妨点击格式标记开关,看看都有哪些格式标记 ...

  3. [python-opencv]模板匹配

    模板匹配最适用于工业场合(在一张图片中识别特定的工件图) 模板匹配是一种最原始.最基本的模式识别方法,研究某一特定对象物的图案位于图像(target)的什么地方,进而识别对象物,这就是一个匹配问题. ...

  4. 网卡配置/etc/network/interfaces

    话说Debian系的网卡配置跟Redhat系很不一样,Redhat是放在/etc/sysconfig/network-scripts目录下面的一大堆文件里面,要修改?你一个一个文件来过吧.Debian ...

  5. sass和css的calc运算

    1.sass不识别不同单位之间的计算,而calc则没问题. width: #{1rem - 2px}; /*出错*/ width: calc(1rem - 2px); 通常情况定制css样式,我不需要 ...

  6. html中载入自执行getElementById("xx")得到null

    <!DOCTYPE HTML> <html> <head> <title>Scope Chain & Closure Example </ ...

  7. android奔溃日期一闪而过

    Android Studio日期崩溃了一闪而过,看不到原因:可以设置No Filters就可以了

  8. 7.MQTT网页客户端连接MQTT服务器的问题WebSocket connection to 'ws://XXX:1883/' failed: Connection closed before receiving a handshake response

    问题描述:MQTT.js提供了连接MQTT的一套javascipt的方法,可供前端连接到MQTT服务器,也可以作为脚本测试.以脚本形式,用nodejs运行,是没有问题的,能够正常连接并且发送报文.但是 ...

  9. jquery两稳定版本比较~~

    jquery历经了多个版本的更新,版本上的比较貌似没什么必要性,一般来说新的版本会比旧的版本各方面都略有提升,但由于新版中增加了各种新的功能,难免会引起bug的发生.评估一个版本是否适合当前开发场景使 ...

  10. ssm返回jsonp数据格式

    为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数 ...