【SCOI2013】摩托车交易 - 最大生成树+树链剖分
题目描述
mzry1992 在打完吊针出院之后,买了辆新摩托车,开始了在周边城市的黄金运送生意。在mzry1992 生活的地方,城市之间是用双向高速公路连接的。另外,每条高速公路有一个载重上限,即在不考虑驾驶员和摩托车重量的情况下,如果所载货物的量超过某个值,则不能驶上该条高速公路。
今年,mzry1992 一共收到了来自n 个不同城市的n 份定订单,每个订单要求卖出上限为一定量的黄金,或是要求买入上限为一定量的黄金。由于订单并不是同时发来的,为了维护生意上的名声,mzry1992 不得不按照订单发来的顺序与客户进行交易。他与第i 个客户进行交易的具体步骤是:
1.前往第i 个客户所在城市。当然,中途是完全允许经过其他城市的。
2.与第i 个客户进行交易,在此过程中他希望有限制的让交易额尽量大。具体的限制有两个
(a) 他希望与最后一个客户完成交易后,手上没有剩余黄金。
(b) 由于黄金是很贵重的物品,不能出现因为买入过多黄金而造成在以后的运送过程中不得不丢弃黄金的情况。
一开始,mzry1992 位于第一个订单客户所在的城市。现在有一个好消息,有人提供了mzry1992 免费试用周边城市的列车系统的资格。具体来讲,如果mzry1992希望从A 城市到达B 城市,且A、B 城市均有列车站的话,他可以携带着黄金与摩托车从A 城市乘坐列车到B 城市,这里假定乘坐列车没有载重限制。
现在已知城市间的交通系统情况和订单情况,请帮助mzry1992 计算每个向mzry1992 购买黄金的客户的购买量。
思路
首先,经过的路径一定在最大生成树上。
其次,不需要考虑交易后剩余黄金的情况,因为可以根据客户的需求而调整买入多少。
这样,跑一遍最大生成树,再用树剖维护树上路径最小值,来看买入多少。
代码
/************************************************
*Author : lrj124
*Created Time : 2019.10.10.21:11
*Mail : 1584634848@qq.com
*Problem : luogu3280
************************************************/
#include <algorithm>
#include <cstring>
#include <cstdio>
#define int ll
using ll = long long;
using namespace std;
const ll inf = 10000000000000ll;
const int maxn = 100000 + 10;
int egcnt,n,m,q,cnt,per[maxn],dep[maxn],father[maxn],top[maxn],num[maxn],val[maxn],Map[maxn],siz[maxn],son[maxn],fir[maxn];
struct Edge { int to,nex; ll w; } eg[maxn];
ll minv[maxn<<2],w[maxn];
struct Road {
int u,v;
ll w;
inline bool operator < (Road cmp) {
return w > cmp.w;
}
} edge[maxn*3];
inline void addedge(int u,int v,ll w) {
eg[++egcnt] = {v,fir[u],w}; fir[u] = egcnt;
eg[++egcnt] = {u,fir[v],w}; fir[v] = egcnt;
}
inline void dfs1(int now,int fa) {
siz[now] = 1;
father[now] = fa;
dep[now] = dep[fa]+1;
for (int i = fir[now];~i;i = eg[i].nex)
if (eg[i].to ^ fa) {
dfs1(eg[i].to,now);
val[eg[i].to] = eg[i].w;
siz[now] += siz[eg[i].to];
if (siz[son[now]] < siz[eg[i].to]) son[now] = eg[i].to;
}
}
inline void dfs2(int now,int ntop) {
num[now] = ++cnt;
Map[cnt] = now;
top[now] = ntop;
if (son[now]) dfs2(son[now],ntop);
for (int i = fir[now];~i;i = eg[i].nex)
if (eg[i].to ^ father[now] && eg[i].to ^ son[now]) dfs2(eg[i].to,eg[i].to);
}
inline void pushup(int root) { minv[root] = min(minv[root<<1],minv[root<<1|1]); }
inline void build(int l,int r,int root) {
if (l == r) {
minv[root] = val[Map[l]];
return;
}
int mid = l+r>>1;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
pushup(root);
}
inline ll query(int l,int r,int ql,int qr,int root) {
if (l > qr || r < ql) return inf;
if (ql <= l && r <= qr) return minv[root];
int mid = l+r>>1;
return min(query(l,mid,ql,qr,root<<1),query(mid+1,r,ql,qr,root<<1|1));
}
inline ll query_edge(int u,int v) {
ll ans = inf;
for (;top[u] ^ top[v];u = father[top[u]]) {
if (dep[top[u]] < dep[top[v]]) swap(u,v);
ans = min(ans,query(1,n,num[top[u]],num[u],1));
}
if (dep[u] > dep[v]) swap(u,v);
return min(ans,query(1,n,num[u]+1,num[v],1));
}
inline int find(int x) { return father[x] = father[x] == x ? x : find(father[x]); }
inline void kruskal() {
for (int i = 1;i <= n;i++) father[i] = i;
if (!q) q = 1;
int cnt = 0;
sort(edge+1,edge+m+q);
for (int i = 1,x,y;i <= m+q-1;i++) {
x = find(edge[i].u);
y = find(edge[i].v);
if (x ^ y) {
father[x] = y;
addedge(edge[i].u,edge[i].v,edge[i].w);
cnt++;
}
if (cnt == n-1) break;
}
memset(father,0,sizeof(father));
}
signed main() {
// freopen("luogu3280.in","r",stdin);
// freopen("luogu3280.out","w",stdout);
memset(fir,-1,sizeof(fir));
scanf("%lld%lld%lld",&n,&m,&q);
for (int i = 1;i <= n;i++) scanf("%lld",&per[i]);
for (int i = 1;i <= n;i++) scanf("%lld",&w[i]);
for (int i = 1;i <= m;i++) scanf("%lld%lld%lld",&edge[i].u,&edge[i].v,&edge[i].w);
for (int i = 1,x,y;i <= q;i++) { scanf("%lld",&x); if (i ^ 1) edge[m+i-1] = {x,y,inf}; y = x; }
kruskal();
dfs1(1,0);
dfs2(1,1);
build(1,n,1);
ll now = 0;
for (int i = 1;i < n;i++)
if (w[per[i]] > 0) now = min(now+w[per[i]],query_edge(per[i],per[i+1]));
else {
printf("%lld\n",min(-w[per[i]],now));
now = min(max(0ll,now+w[per[i]]),query_edge(per[i],per[i+1]));
}
if (w[per[n]] < 0) printf("%lld",min(-w[per[n]],now));
return 0;
}
【SCOI2013】摩托车交易 - 最大生成树+树链剖分的更多相关文章
- BZOJ3322[Scoi2013]摩托车交易——最大生成树+贪心+倍增
题目描述 mzry1992 在打完吊针出院之后,买了辆新摩托车,开始了在周边城市的黄金运送生意.在mzry1992 生活的地方,城市之间是用双向高速公路连接的.另外,每条高速公路有一个载重上限,即在不 ...
- NOIP2013D1T3货车运输 (生成树+树链剖分)
给出一个图,询问图上两点间路径上最小边权的最大值. 先跑一次最大生成树. 树剖维护路径最小边权. 树剖又双叒叕写挂了. #include<cstring> #include<cstd ...
- NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】
NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...
- [wikioi 1519]过路费(最小生成树+树链剖分)
题目:http://www.wikioi.com/problem/1519/ 题意:给你一个连通的无向图,每条边都有权值,给你若干个询问(x,y),要输出从x到y的路径上边的最大值的最小值 分析:首先 ...
- Educational Codeforces Round 3 E. Minimum spanning tree for each edge (最小生成树+树链剖分)
题目链接:http://codeforces.com/contest/609/problem/E 给你n个点,m条边. 问枚举每条边,问你加这条边的前提下组成生成树的权值最小的树的权值和是多少. 先求 ...
- BZOJ 1103: [POI2007]大都市meg( 树链剖分 )
早上数学考挂了...欲哭无泪啊下午去写半个小时政治然后就又可以来刷题了.. 树链剖分 , 为什么跑得这么慢... ------------------------------------------- ...
- Educational Codeforces Round 3 E. Minimum spanning tree for each edge 最小生成树+树链剖分+线段树
E. Minimum spanning tree for each edge time limit per test 2 seconds memory limit per test 256 megab ...
- 1103. [POI2007]MEG-Megalopolis【树链剖分】
Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了. 不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1.. ...
- 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树
题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...
随机推荐
- for循环实现Fibonacci数列
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n. 输出格 ...
- 使用java实现希表的基础功能
用java代码完成哈希表数据结构的简单实现, 以公司雇员的添加修改作为模拟实例 具体代码如下: package com.seizedays.hashtable; import java.util.Sc ...
- HttpServletRequest、HttpServletResponse
doGet()/doPost()方法都有两个参数,一个为代表请求的request,另一个代表响应response. request是获取前台传递的内容,response是反馈给前台数据 HttpSer ...
- 解决node 运行接口 出现 Cannot destructure property `us` of 'undefined' or 'null'.
出现 参数是 undefined or null 一.检查是否安装 body-parser server.js中是否引入 app.use(bodyParser.urlencoded({ extende ...
- 解决SyntaxError: Non-UTF-8 code starting with '\xbb'问题
在第一行加入 # coding=utf-8 2020-06-13
- pandas_使用透视表与交叉表查看业绩汇总数据
# 使用透视表与交叉表查看业绩汇总数据 import pandas as pd import numpy as np import copy # 设置列对齐 pd.set_option("d ...
- PHP ezmlm_hash() 函数
定义和用法 ezmlm_hash() 函数用于在 MySQL 数据库中保存 EZMLM 邮件列表的哈希值. 该函数接收一个 Email 地址参数,返回一个整数哈希值. 语法 int ezmlm_has ...
- PHP zip_entry_compressedsize() 函数
定义和用法 zip_entry_compressedsize() 函数返回 zip 档案项目的压缩文件尺寸.高佣联盟 www.cgewang.com 语法 zip_entry_compressedsi ...
- Skill 脚本演示 ycNetToPin.il
https://www.cnblogs.com/yeungchie/ ycNetToPin.il 通过选中一个 instance ,分析与其连接且同时选中的 wire 上含有的 netName ,自动 ...
- 7.1 NOI模拟赛 凸包套凸包 floyd 计算几何
计算几何之所以难学 就是因为太抽象了 不够直观 而且情况很多 很繁琐 甚至有一些东西不清不楚.. 这道题注意到题目中的描述 一个鸽子在两个点所连直线上也算. 通过看题解 发现这个地方并非直线而是线段 ...