Wannafly挑战赛2_D Delete(拓扑序+最短路+线段树)
Wannafly挑战赛2_D Delete
Problem :
给定一张n个点,m条边的带权有向无环图,同时给定起点S和终点T,一共有q个询问,每次询问删掉某个点和所有与它相连的边之后S到T的最短路,询问之间互相独立(即删除操作在询问结束之后会立即撤销),如果删了那个点后不存在S到T的最短路,则输出-1。
n,q <= 10^5
Solution :
注意到题中所给的是DAG,首先可以找出图中结点的拓扑序。对于删除掉某个点之后,若仍存在一条从S到T的最短路,那么对应到拓扑序中,必然有一条边跨过了该点(即这条边的两个端点的拓扑序在这个点的两边)。故对于每条边(u, v, w), 对拓扑序(a[u], a[v])中的点提供了一条长度为ds[u]+dt[v]+w的最短路,用线段树来维护最小值。
注意特判若u->v不可能经过这个点,那么直接输出最短路。
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
const long long INF = 1ll << 60;
const int N = 1e5 + 8;
struct edge
{
int v, w;
edge(int v = 0, int w = 0):v(v),w(w){}
};
vector <edge> vec[N], vec2[N];
long long ds[N], dt[N];
int a[N], deg[N];
int n, m, S, T;
void init()
{
cin >> n >> m >> S >> T;
for (int i = 1; i <= n; ++i) vec[i].clear(), vec2[i].clear();
for (int i = 1; i <= m; ++i)
{
int u, v, w; cin >> u >> v >> w;
vec[u].push_back(edge(v, w));
vec2[v].push_back(edge(u, w));
deg[v]++;
}
}
void getDag()
{
static queue <int> Q;
int tot = 0;
for (int i = 1; i <= n; ++i)
{
if (deg[i] == 0)
{
a[i] = ++tot;
Q.push(i);
}
}
while (!Q.empty())
{
int u = Q.front(); Q.pop();
for (auto p : vec[u])
{
deg[p.v]--;
if (deg[p.v] == 0)
{
a[p.v] = ++tot;
Q.push(p.v);
}
}
}
}
struct node
{
int u;
long long w;
bool operator < (const node &b) const
{
return w > b.w;
}
};
void Dijkstra(int S, long long dis[], vector <edge> vec[])
{
static priority_queue<node> Q;
static bool vis[N];
for (int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0;
Q.push((node){S, 0});
dis[S] = 0;
while (!Q.empty())
{
int u = Q.top().u; Q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto p : vec[u])
if (dis[u] + p.w < dis[p.v])
{
dis[p.v] = dis[u] + p.w;
Q.push((node{p.v, dis[p.v]}));
}
}
}
class SegmentTree
{
public:
long long tag[N << 2];
void build(int l, int r, int rt)
{
tag[rt] = INF;
if (l == r) return;
int m = l + r >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
}
void update(int L, int R, long long val, int l, int r, int rt)
{
// if (l == 1 && r == n) cout << L << " " << R << " " << val << endl;
if (L <= l && r <= R)
{
tag[rt] = min(tag[rt], val);
return;
}
int m = l + r >> 1;
if (L <= m) update(L, R, val, l, m, rt << 1);
if (m < R) update(L, R, val, m + 1, r, rt << 1 | 1);
}
void query(int x, int l, int r, int rt, long long &ans)
{
ans = min(ans, tag[rt]);
if (l == r) return;
int m = l + r >> 1;
if (x <= m) query(x, l, m, rt << 1, ans);
else query(x, m + 1, r, rt << 1 | 1, ans);
}
}ST;
void buildSeg()
{
ST.build(1, n, 1);
for (int u = 1; u <= n; ++u)
for (auto p : vec[u])
if (a[u] + 1 < a[p.v] && ds[u] != INF && dt[p.v] != INF)
{
// cout << u << " " << p.v << " " << a[u] << " " << a[p.v] << endl;
ST.update(a[u] + 1, a[p.v] - 1, ds[u] + dt[p.v] + p.w, 1, n, 1);
}
}
void solve()
{
int Q; cin >> Q;
for (; Q; --Q)
{
int u; cin >> u;
long long ans = INF;
if (ds[u] == INF || dt[u] == INF)
{
cout << dt[S] << endl;
continue;
}
ST.query(a[u], 1, n, 1, ans);
if (ans == INF) cout << -1 << endl; else cout << ans << endl;
}
}
int main()
{
cin.sync_with_stdio(0);
init();
getDag();
Dijkstra(S, ds, vec);
Dijkstra(T, dt, vec2);
buildSeg();
solve();
}
Wannafly挑战赛2_D Delete(拓扑序+最短路+线段树)的更多相关文章
- 【Wannafly挑战赛29F】最后之作(Trie树,动态规划,斜率优化)
[Wannafly挑战赛29F]最后之作(Trie树,动态规划,斜率优化) 题面 牛客 题解 首先考虑怎么计算\([l,r]\)这个子串的不同的串的个数. 如果\(l=1\),我们构建\(Trie\) ...
- Codeforces Round #442 (Div. 2) E Danil and a Part-time Job (dfs序加上一个线段树区间修改查询)
题意: 给出一个具有N个点的树,现在给出两种操作: 1.get x,表示询问以x作为根的子树中,1的个数. 2.pow x,表示将以x作为根的子树全部翻转(0变1,1变0). 思路:dfs序加上一个线 ...
- 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树
题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...
- hdu5692【dfs序】【线段树】
Snacks Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...
- Wannafly挑战赛2 D.Delete(拓扑排序 + dij预处理 + 线段树维护最小值)
题目链接 D.Delete 考虑到原图是个DAG,于是我们可以求出每个点的拓扑序. 然后预处理出起点到每个点的最短路$ds[u]$, 和所有边反向之后从终点出发到每个点的最短路$dt[u]$. 令点 ...
- Wannafly挑战赛2D Delete (最短路好题)
大意: 给定DAG, 给定点$S,T$, 每次询问给出点$x$, 求删除$x$后的$S->T$的最短路, 询问之间独立. 删除点$x$的最短路一定要经过一条边$(u,v)$, 满足$u$拓扑序在 ...
- [BZOJ4699]树上的最短路(最短路+线段树)
https://www.cnblogs.com/Gloid/p/10273902.html 这篇文章已经从头到尾讲的非常清楚了,几乎没有什么需要补充的内容. 首先$O(n\log^2 n)$的做法比较 ...
- BZOJ4400 TJOI2012桥(最短路+线段树)
首先找出任意一条1-n的最短路径.显然删除的边只有在该最短路上才会对最短路长度产生影响. 不会证明地给出一个找不到反例的结论:删除一条边后,新图中一定有一条1-n的最短路径上存在一条边x->y, ...
- 【62测试】【状压dp】【dfs序】【线段树】
第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...
随机推荐
- P3371 【模板】单源最短路径
题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...
- android动画之通过子线程来实现动画
android动画之通过子线程来实现动画 使用android动画机制,往往是相对于原始位置来进行参照. 这里通过子线程修改物体位置实现动画. 布局文件: <RelativeLayout xmln ...
- spark性能优化-JVM虚拟机垃圾回收调优
1 2 3 4
- (转)用@Resource注解完成属性装配
http://blog.csdn.net/yerenyuan_pku/article/details/52858878 前面我们讲过spring的依赖注入有两种方式: 使用构造器注入. 使用属性set ...
- Java8函数式编程和lambda表达式
文章目录函数式编程JDK8接口新特性函数接口方法引用函数式编程函数式编程更多时候是一种编程的思维方式,是一种方法论.函数式与命令式编程区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉 ...
- uva1613 K-Graph Oddity
题目要求k>=最大度数:观察,颜色数量和度数的关系,得颜色数=最大度数+1(偶数)//最大度数(奇数) 可以满足染色关系一个点和周围的点的颜色数加起来最大为它的度数+1: k=所有点中最大的度. ...
- drawer 抽屉 弹框 在 modal的后面的解决方案
drawer 抽屉 弹框 在 modal的后面的解决方案 方案1 在框内 弹出 <Drawer title="拍照" :transfer="false" ...
- @click.native 会触发原生 click事件 vue
@click.native 会触发原生 click事件 vue
- 【搜索】P1219 八皇后
题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...
- PHP09 字符串和正则表达式
学习要点 字符串处理简介 常用的字符串输出函数 常用的字符串格式化函数 字符串比较函数 正则表达式简介 正则表达式语法规则 与perl兼容的正则表达式函数 字符串处理介绍 Web开发中字符串处理 ...