二分答案+树链剖分+树上差分

我们假设x是最小的花费,可以想到给定x,所有运输计划中花费大于x的计划必须经过虫洞,且最长的一条的花费减去虫洞所在边的花费要小于等于x

那么对于x,虫洞所在的位置肯定是确定的,假设x可以取更小,那么就没有一个合法方案可以放虫洞,x取更大,显然该方案也合法,这是一个明显符合单调性的问题,我们可以用二分答案求解。

其实最大值最小就是答案具有单调性的特征啦。。

通过上述分析,我们可以确定虫洞所在位置就是花费大于x的运输计划的交,即该边被覆盖次数等于花费大于x的运输计划数,那么对于每个x,我们可以用树上边差分的方式来求出交。

如何求最大的花费呢?我们考虑差分时要求LCA,且要求出树上的路径,那么树链剖分就再好不过了!

在dfs1的时候我们就需要吧边权塞给点(便是该点到其父亲的权值),然后通过树链剖分把LCA,和两点花费求出来。最后用max维护最大即可。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int X = 0, w = 0; char ch = 0;
while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
}
const int N = 300005;
int n, m, cnt, dfn, head[N], size[N], p[N], son[N], depth[N], top[N], w[N], val[N], id[N], tmp[N];
int tree[N<<2], num, len, ml, ans;
struct Edge { int v, next, w; } edge[N<<1];
struct Ask {
int u, v, lca, dis;
bool operator < (const Ask &rhs) const {
return dis > rhs.dis;
}
} ask[N<<1]; void addEdge(int a, int b, int w){
edge[cnt].v = b, edge[cnt].w = w, edge[cnt].next = head[a], head[a] = cnt ++;
} void dfs1(int s, int fa){
depth[s] = depth[fa] + 1;
p[s] = fa;
size[s] = 1;
int child = -1;
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(u == fa) continue;
dfs1(u, s);
size[s] += size[u], val[u] = edge[i].w;
if(size[u] > child) child = size[u], son[s] = u;
}
} void dfs2(int s, int tp){
id[s] = ++dfn;
w[id[s]] = val[s];
top[s] = tp;
if(son[s] != -1) dfs2(son[s], tp);
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(u == p[s] || u == son[s]) continue;
dfs2(u, u);
}
} void push_up(int rt){
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
} void buildTree(int rt, int l, int r){
if(l == r){
tree[rt] = w[l];
return;
}
int mid = (l + r) >> 1;
buildTree(rt << 1, l, mid);
buildTree(rt << 1 | 1, mid + 1, r);
push_up(rt);
} int query(int rt, int l, int r, int queryL, int queryR){
if(queryL > queryR) return 0;
if(l == queryL && r == queryR){
return tree[rt];
}
int mid = (l + r) >> 1;
if(queryL > mid) return query(rt << 1 | 1, mid + 1, r, queryL, queryR);
else if(queryR <= mid) return query(rt << 1, l, mid, queryL, queryR);
else return query(rt << 1, l, mid, queryL, mid) +
query(rt << 1 | 1, mid + 1, r, mid + 1, queryR);
} void lca(int x, int y, int k){
int v = 0;
while(top[x] != top[y]){
if(depth[top[x]] < depth[top[y]]) swap(x, y);
v += query(1, 1, n, id[top[x]], id[x]);
x = p[top[x]];
}
if(depth[x] > depth[y]) swap(x, y);
v += query(1, 1, n, id[x] + 1, id[y]);
ask[k].lca = x, ask[k].dis = v;
} void dfs3(int s, int fa){
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(u == fa) continue;
dfs3(u, s);
tmp[s] += tmp[u];
}
if(s != 1 && tmp[s] == num && val[s] > len) len = val[s];
} bool check(int x){
num = 0, len = -INF, ml = -INF;
full(tmp, 0);
int i = 0;
for(; i < m; i ++){
if(ask[i].dis <= x) break;
int u = ask[i].u, v = ask[i].v, f = ask[i].lca;
tmp[u] ++, tmp[v] ++, tmp[f] -= 2;
num ++;
ml = max(ml, ask[i].dis);
}
if(i == 0) return true;
dfs3(1, 0);
return ml - len <= x;
} void solve(){
sort(ask, ask + m);
int l = 0, r = ask[0].dis;
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
ans = l;
} int main(){ full(head, -1);
full(son, -1);
n = read(), m = read();
for(int i = 0; i < n - 1; i ++){
int u = read(), v = read(), w = read();
addEdge(u, v, w), addEdge(v, u, w);
}
dfs1(1, 0), dfs2(1, 1);
buildTree(1, 1, n);
for(int i = 0; i < m; i ++){
ask[i].u = read(), ask[i].v = read();
//cout << i << " " << ask[i].u << " " << ask[i].v << endl;
lca(ask[i].u, ask[i].v, i);
}
solve();
printf("%d\n", ans);
return 0;
}

BZOJ 4326 运输计划的更多相关文章

  1. NOIP 2015 BZOJ 4326 运输计划 (树链剖分+二分)

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

  2. BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 1388  Solved: 860 [Submit][Stat ...

  3. bzoj 4326: NOIP2015 运输计划

    4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MB Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个 ...

  4. 【BZOJ 4326】【NOIP2015】运输计划

    http://www.lydsy.com/JudgeOnline/problem.php?id=4326 题目描述 公元2044年,人类进入了宇宙纪元. 国有个星球,还有条双向航道,每条航道建立在两个 ...

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

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

  6. BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

    NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所 ...

  7. bzoj 4326: NOIP2015 运输计划(二分+树链剖分)

    传送门 题解: 树链剖分快速求解任意两点间的路径的权值和: 然后,二分答案: 此题的难点是如何快速求解重合路径? 差分数组可以否??? 在此之前先介绍一下相关变量: int fa[maxn]; int ...

  8. BZOJ 4326: NOIP2015 运输计划(二分,树上差分)

    Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1945  Solved: 1243[Submit][Status][Discuss] Descript ...

  9. bzoj 4326: NOIP2015 运输计划【树链剖分+二分+树上差分】

    常数巨大,lg上开o2才能A 首先预处理出运输计划的长度len和lca,然后二分一个长度w,对于长度大于w的运输计划,在树上差分(d[u]+1,d[v]+1,d[lca]-2),然后dfs,找出所有覆 ...

随机推荐

  1. MyEclipse和eclipse的区别

    对于新手来说,MyEclipse和eclipse来说的区别可能就是MyEclipse比eclipse多了my,MyEclipse主要为JavaEE开发,而Eclipse主要为Java开发..那么MyE ...

  2. 书城项目第五阶段---book表的curd

    JavaEE三层架构分析 MVC

  3. p201 谱集是闭集 有界集

    1 是如何来的?  由1 如何推出 2 2 是如何来的?谢谢 1.σ是的补集 入属于ρ  稠密是因为   T有定义的地方,λI-T都有定义,有界是因为 所以 然后 ρ是σ的补集 模比||T||大的数都 ...

  4. mysql数据从windows导出,再导入到linux

    从windows导出时,要注意字符集最好和linux的一致,如linux字符集一般为utf8,则导出时可以加上参数--default-character-set=utf8指定字符集,然后导入到linu ...

  5. 自己实现数据结构系列四---Queue

    一.代码部分 1.定义接口: public interface Queue<E> { void enqueue(E e); E dequeue(); E getFront(); int g ...

  6. rest framwork 小试身手

    models.py from django.db import models class Course(models.Model): """ 课程表 "&quo ...

  7. yum 命令

    yum( Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器. 基於RPM包管理,能够从指定的服务器自动下载RPM包 ...

  8. TCP 握手和挥手图解(有限状态机)

    1.引言 TCP 这段看过好几遍,老是记不住,没办法找工作涉及到网络编程这块,各种问 TCP .今天好好整理一下握手和挥手过程.献给跟我一样忙碌,找工作的童鞋,欢迎大神批评指正. 2.TCP 的连接建 ...

  9. react 路由4 学习

    表单控件 受控表单组件 非受控的表单组件 demo:收集表单提交的数据 路由(V4) 特点:一切皆是组件 官网:https://reacttraining.com/react-router/ npm ...

  10. MySQL经典编程问题

    星期数的问题 1 计算日期是周几 这个问题看似很简单,可以用MySQL内置函数来计算 (1) weekday(date)其返回值是0-6,0代表Monday, 6代表Sunday: (2) dayof ...