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(拓扑序+最短路+线段树)的更多相关文章

  1. 【Wannafly挑战赛29F】最后之作(Trie树,动态规划,斜率优化)

    [Wannafly挑战赛29F]最后之作(Trie树,动态规划,斜率优化) 题面 牛客 题解 首先考虑怎么计算\([l,r]\)这个子串的不同的串的个数. 如果\(l=1\),我们构建\(Trie\) ...

  2. 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序加上一个线 ...

  3. 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树

    题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...

  4. hdu5692【dfs序】【线段树】

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  5. Wannafly挑战赛2 D.Delete(拓扑排序 + dij预处理 + 线段树维护最小值)

    题目链接  D.Delete 考虑到原图是个DAG,于是我们可以求出每个点的拓扑序. 然后预处理出起点到每个点的最短路$ds[u]$, 和所有边反向之后从终点出发到每个点的最短路$dt[u]$. 令点 ...

  6. Wannafly挑战赛2D Delete (最短路好题)

    大意: 给定DAG, 给定点$S,T$, 每次询问给出点$x$, 求删除$x$后的$S->T$的最短路, 询问之间独立. 删除点$x$的最短路一定要经过一条边$(u,v)$, 满足$u$拓扑序在 ...

  7. [BZOJ4699]树上的最短路(最短路+线段树)

    https://www.cnblogs.com/Gloid/p/10273902.html 这篇文章已经从头到尾讲的非常清楚了,几乎没有什么需要补充的内容. 首先$O(n\log^2 n)$的做法比较 ...

  8. BZOJ4400 TJOI2012桥(最短路+线段树)

    首先找出任意一条1-n的最短路径.显然删除的边只有在该最短路上才会对最短路长度产生影响. 不会证明地给出一个找不到反例的结论:删除一条边后,新图中一定有一条1-n的最短路径上存在一条边x->y, ...

  9. 【62测试】【状压dp】【dfs序】【线段树】

    第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...

随机推荐

  1. /usr/bin/install -c -m 644 sample-config/httpd.conf /etc/httpd/conf.d/nagios.conf

    [root@localhost nagios]# make install-webconf/usr/bin/install -c -m 644 sample-config/httpd.conf /et ...

  2. 51nod 1267 4个数和为0

    基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出"Yes",否则输出&qu ...

  3. js&jquery页面加载完执行

    js <script type=”text/javascript”> window.onload=function (){ var userName=”xiaoming”; alert(u ...

  4. Maven实战读书笔记(一):Maven概述

    1.1 Maven是什么,能做什么 Maven是一个跨平台的项目管理工具,主要服务于Java平台的项目构建.依赖管理和项目信息管理. Maven的用途之一是项目构建,能够自动化构建过程,从清理.编译. ...

  5. scanf_s读取键盘输入字符串失败

    #include<stdio.h> int main() { ]; ]; printf("Input string:\n"); scanf_s("%s&quo ...

  6. oracle数字返回为字符串时小时点前面的0缺失的问题

    SELECT 0.001||'' from dual UNION SELECT TO_CHAR(0.001||'','fm999990.99999') from dual;

  7. 解决 【xshell 5 不能使用退格键和Delete建】的问题

    ###按照图片操作即可 1,打开[文件],选择[打开]选项 2.在会话中,打开[属性] 3.点击左边[终端]下的[键盘]选项,按照如下设置 即可.

  8. Spring AOP 详细介绍

    一.理解 “面向切面编程” 面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Prog ...

  9. 如何用纯 CSS 创作一种有削铁如泥感觉的菜单导航特效

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/XqYroe 可交互视频教 ...

  10. HTML中复选框的使用方法

    <select id="question"> {# 常见问题.ajax用editor.html('1231254')填充#} <option value=&quo ...