【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巨型计算 ...
随机推荐
- sql 大小写查询 字符串替换 小写xx 改为大写XX
--sql 大小写查询 select * from 表 where 字段 collate Chinese_PRC_CS_AS='xx' --替换 小写xx 改为大写XX update 表 set ...
- Docker 入门教程(4)——docker-compse 服务编排
Docker compose 简介 compose是用来定义和运行多个Docker容器. 比如一个简单的web项目,除了web服务之外,我们可能要需要数据库容器.注册中心容器等等.那我们需要: 定义各 ...
- python Scrapy 从零开始学习笔记(一)
在之前我做了一个系列的关于 python 爬虫的文章,传送门:https://www.cnblogs.com/weijiutao/p/10735455.html,并写了几个爬取相关网站并提取有效信息的 ...
- python-闭包和装饰器-02-装饰器(decorator)
装饰器(decorator) 理解了上一章的闭包之后,装饰器就是闭包的一种应用,只是外部函数的参数传入的不是普通的变量类型,而是传入一个函数名.装饰器一般用于:不修改被装饰函数(即外部函数传入的参数) ...
- AndroidStudio查找硬编码的String字符串
在Menu的“Analyze”中,选择“Run Inspection By Name”,然后输入“Hardcoded strings”,执行后,可以找到所有没有加入strings.xml的字符串. 按 ...
- 2n皇后问题-------递归 暴力求解题与分布讨论题
问题描述 给定一个n*n的棋盘,棋盘中有一些位置不能放皇后.现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行.同一列或同一条对角线上,任意的两个白皇后都不在同一行.同一列或同一 ...
- selenium 破解登录滑块验证码mu
from selenium import webdriverfrom PIL import Imagefrom selenium.webdriver import ChromeOptionsfrom ...
- laravel报错1071 Specified key was too long; max key length is 1000 bytes
Laravel 默认使用utf8mb4字符编码,而不是的utf8编码.因此运行php artisan migrate会出现如下错误: [Illuminate\Database\QueryExcepti ...
- python map函数、filter函数、reduce函数
1.map函数:map(func,可迭代对象): ①func可以是自定义的函数,也可以是功能简单的匿名函数(通过lambda定义) ②处理逻辑:表示将传入的可迭代对象依次循环,将每个元素按照传入的fu ...
- 为PhpStorm添加Laravel 代码智能提示功能
php artisan clear-compiled //清除bootstrap/compiled.php php artisan ide-helper:generate //为 Facades 生成 ...