「BZOJ 4289」 PA2012 Tax
「BZOJ 4289」 PA2012 Tax
题目描述
给出一个 \(N\) 个点 \(M\) 条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点 \(1\) 到点 \(N\) 的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权
\(N \leq 10^5, M \leq 2 \times 10^5\)
### 解题思路 :
首先考虑一个暴力的做法,建一个新图,把每一条边看成新图的一个点‘
对于原图的每一个点 \(u\) 对于边 \((u, x), (u, y)\) 在新图中连边 \((u, x) \rightarrow (u, y) = \max(val_{(u, x)}, val_{(u, y)})\)
这样做的复杂度是 \(O(\sum deg_u^2 logn)\),一个菊花图就 \(TLE\) 了

考虑简化新图的边数,不妨观察新图的是怎么得到的
对于原图的一个点,所有与其相邻的连的边在新图都两两连边,其表示从一条边进这个点,从一条边出这个点,边权是两条边的 \(\max\)
观察发现,虽然原图一个点在新图中能产生的边多达 \(deg^2\) 条,但是边的权值只有最多 \(deg\) 种
不妨对原图一个点周围的边按照权值从小到大排序,相邻两条边连一条 \(i \rightarrow i+1\) 的有向边,权值为 \(val_{i+1} - val_i\)
那么从一条较小的边进去,从一条较大的边出来的话,一路经过的权值和恰好等于较大的边的权值
但是可能是从较大的边进入一个点,同时判断走这条边是否真的离开了这个点也很困难,于是就需要分类讨论了
观察发现,可以把一个点周围的边按照权值排序后看成一个环,答案的形态就是从一个环经过一些环内的边再通过一条环边到达另外一个环,以此反复
那么不妨把新图的一个点拆成两个点,\(u\) 表示这个点此时属于原图编号较小的点对应的环, \(u'\) 表示属于原图编号较大的点对应的环
考虑每当从一个环进到另外一个环时,设一个初始权值 $x $ 等于入环的边的边权,如果 \(x\) 是较小的边,那么沿着边权为 \(val_{i+1} - val_i\) 的有向边出环,否则就走边权为 \(0\) 的有向边出环,这样保证了出环时的权值正确
所以只需要对于每个点的相连边按照权值排序后,从小到大相邻的点连 \(val_i+1 - val_i\) 的有向边,从大到小连边为 \(0\) 的有向边,然后在出环的时候 \(u\) 和 \(u'\) 连一条权值为 \(val_u\) 的无向边即可,这样点数是 \(O(2m)\),边数是 \(O(3m)\)
注意要保证同一个环内连的边其对应的端点是同一个,而不是全都是 \(u\) 或 \(u'\) ,剩余的只需要跑一遍 \(Dijkstra\) 即可
复杂度是\(O(mlogm)\)
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf ((ll) (1e18))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define int ll
const int N = 2000005;
int a[N], b[N], nxt[N], head[N], cnt;
int dis[N], n, m;
struct Edge{
int id, x, y, val;
inline int bel(int u){ return (int)(min(x, y) == u); }
}; vector<Edge> g[N];
inline bool cmp(Edge A, Edge B){ return A.val < B.val; }
inline void add(int x, int y, int z){
a[++cnt] = y, b[cnt] = z, nxt[cnt] = head[x], head[x] = cnt;
}
inline void Addedge(int u){
// x + m表示边 x 挂在编号较小的点围成的环上所产生的节点
// x 表示边 x 挂在编号较大的点围城的环上所产生的节点
// 同编号环(x -> y) 小到大 val = y.val - x.val
// 同编号环(x -> y) 大到小 val = 0
// 异编号环(x -> y) 小到大/大到小 val = y.val
sort(g[u].begin(), g[u].end(), cmp);
for(int i = 0, x, y; i < g[u].size(); i++){
if(i){
x = g[u][i].id + g[u][i].bel(u) * m;
y = g[u][i-1].id + g[u][i-1].bel(u) * m;
add(x, y, 0);
}
if(i < g[u].size() - 1){
x = g[u][i].id + g[u][i].bel(u) * m;
y = g[u][i+1].id + g[u][i+1].bel(u) * m;
add(x, y, g[u][i+1].val - g[u][i].val);
}
x = g[u][i].id + g[u][i].bel(u) * m;
y = g[u][i].id + (g[u][i].bel(u) ^ 1) * m;
add(x, y, g[u][i].val);
}
}
struct Node{
int d, id;
bool operator < (const Node &A) const{ return d > A.d; }
}; priority_queue<Node> pq;
inline void Dijkstra(int S){
for(int i = 0; i <= 2 * m + 1; i++) dis[i] = inf / 3;
pq.push((Node){0, S}), dis[S] = 0;
while(!pq.empty()){
Node now = pq.top(); pq.pop();
int u = now.id;
if(dis[u] != now.d) continue;
if(u == 2 * m + 1) return;
for(int p = head[u]; p; p = nxt[p]){
int v = a[p];
if(dis[v] > dis[u] + b[p])
dis[v] = dis[u] + b[p], pq.push((Node){dis[v], v});
}
}
}
signed main(){
read(n), read(m);
for(int i = 1, x, y, z; i <= m; i++){
read(x), read(y), read(z);
g[x].push_back((Edge){i, x, y, z});
g[y].push_back((Edge){i, y, x, z});
}
for(int i = 1; i <= n; i++) Addedge(i);
for(int i = 0; i < g[1].size(); i++) add(0, g[1][i].id + m, g[1][i].val);
for(int i = 0; i < g[n].size(); i++) add(g[n][i].id, 2 * m + 1, 0);
Dijkstra(0), cout << dis[2*m+1];
return 0;
}
「BZOJ 4289」 PA2012 Tax的更多相关文章
- 「BZOJ 4228」Tibbar的后花园
「BZOJ 4228」Tibbar的后花园 Please contact lydsy2012@163.com! 警告 解题思路 可以证明最终的图中所有点的度数都 \(< 3\) ,且不存在环长是 ...
- 「BZOJ 3645」小朋友与二叉树
「BZOJ 3645」小朋友与二叉树 解题思路 令 \(G(x)\) 为关于可选大小集合的生成函数,即 \[ G(x)=\sum[i\in c ] x^i \] 令 \(F(x)\) 第 \(n\) ...
- 「BZOJ 4502」串
「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...
- 「BZOJ 2534」 L - gap字符串
「BZOJ 2534」 L - gap字符串 题目描述 有一种形如 \(uv u\) 形式的字符串,其中 \(u\) 是非空字符串,且 \(v\) 的长度正好为 \(L\), 那么称这个字符串为 \( ...
- 「BZOJ 2956」模积和
「BZOJ 2956」模积和 令 \(l=\min(n,m)\).这个 \(i\neq j\) 非常不优雅,所以我们考虑分开计算,即: \[\begin{aligned} &\sum_{i=1 ...
- Solution -「BZOJ 3812」主旋律
\(\mathcal{Description}\) Link. 给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...
- 「BZOJ 1001」狼抓兔子
题目链接 luogu bzoj \(Solution\) 这个貌似没有什么好讲的吧,直接按照这个给的图建图就好了啊,没有什么脑子,但是几点要注意的: 建双向边啊. 要这么写,中间还要写一个\(whil ...
- 「BZOJ 5188」「Usaco2018 Jan」MooTube
题目链接 luogu bzoj \(Describe\) 有一个\(n\)个节点的树,边有权值,定义两个节点之间的距离为两点之间的路径上的最小边权 给你\(Q\)个询问,问你与点\(v\)的距离大于等 ...
- 「BZOJ 1791」「IOI 2008」Island「基环树」
题意 求基环树森林所有基环树的直径之和 题解 考虑的一个基环树的直径,只会有两种情况,第一种是某个环上结点子树的直径,第二种是从两个环上结点子树内的最深路径,加上环上这两个结点之间的较长路径. 那就找 ...
随机推荐
- 【BZOJ】3143: [Hnoi2013]游走 期望+高斯消元
[题意]给定n个点m条边的无向连通图,每条路径的代价是其编号大小,每个点等概率往周围走,要求给所有边编号,使得从1到n的期望总分最小(求该总分).n<=500. [算法]期望+高斯消元 [题解] ...
- 【BZOJ】3527: [Zjoi2014]力 FFT
[参考]「ZJOI2014」力 - FFT by menci [算法]FFT处理卷积 [题解]将式子代入后,化为Ej=Aj-Bj. Aj=Σqi*[1/(i-j)^2],i=1~j-1. 令f(i)= ...
- 面向对象 ( OO ) 的程序设计——继承
本文地址:http://www.cnblogs.com/veinyin/p/7608282.html 仅支持实现继承,且主要依靠原型链来实现,不过一般会混合构造函数一起实现继承 1 原型链 继承使用 ...
- 【leetcode 简单】 第五十一题 有效电话号码
给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,写一个 bash 脚本输出所有有效的电话号码. 你可以假设一个有效的电话号码必须满足以下两种格式: (xxx) xxx-xxx ...
- NYOJ 267 郁闷的C小加(二) (字符串处理)
题目链接 描述 聪明的你帮助C小加解决了中缀表达式到后缀表达式的转换(详情请参考"郁闷的C小加(一)"),C小加很高兴.但C小加是个爱思考的人,他又想通过这种方法计算一个表达式的值 ...
- 再续 virtualenv II
为什么搭建虚拟环境 搭建 Python 虚拟环境,可以方便的解决不同项目中对类库的依赖问题.当然,也可以方便地Python2,Python3 共存.避免包的混乱和版本的冲突.为每个程序单独创建虚拟环境 ...
- 老版本ubuntu更新源地址以及sources.list的配置方法 转
转自(http://blog.csdn.net/snaking616/article/details/52966634) 1.国内可用的更新源地址: (1)中科大地址 http://mirrors.u ...
- koa中间层 文件下载的请求转发
背景: 前端用a标签发起下载文档的get请求 node中间层接到get请求后将请求转发到java后端 java后端返回文档流传递给node中间层 好处: 后端的java业务逻辑层接口.数据库不向外部暴 ...
- 以太坊go-ethereum客户端查询交易列表(二)
玩过比特币的朋友都知道,比特币是可以通过api(listtransactions)查询指定地址的历史交易的.但在eth中没有提供类似的查询api.今天这篇博客就简单介绍一下如果解决这个问题. 问题 以 ...
- hdu 1849(巴什博弈)
Rabbit and Grass Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...