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. re正则表达式公式讲解3

    1.分组匹配    用()把需要分组的类型括起来,如下 import re m = re.search("([a-z]+)([0-9]+)","alex123" ...

  2. canvas基础绘制-倒计时(上)

    效果: html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  3. 【java基础】Java锁机制

    在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁(广义) 互斥锁/读写锁(独享锁/共享锁的实现) 乐观锁 ...

  4. Synplify FPGA 逻辑综合

    作为 Synopsys FPGA 设计解决方案的一部分,Synplify FPGA 综合软件是实现高性能.高性价比的 FPGA 设计的行业标准. 其独特的行为提取综合技术 (Behavior Extr ...

  5. MyBatis学习(四)

    前言 最近比较松懈,下班回家后也懒得学习了.今晚实在是看不下去了,争取时间学习.社会上有这么多的资源,就看谁能抢的多吧.今天就说说MyBatis的动态SQL吧 正文 动态 SQL 通常要做的事情是有条 ...

  6. Linux系统使用iftop查看带宽占用情况

    Linux系统下如果服务器带宽跑满了,查看跟哪个ip通信占用带宽比较多,可以通过iftop命令进行查询,使用方法如下: 1 安装方法[软件官网地址:http://www.ex-parrot.com/~ ...

  7. xcopy递归拷贝

    递归拷贝 ::xcopy SOURCE_DIR DES_DIR\ /s SOURCE_DIR后面不需要加反斜杠

  8. C# 移动开发(Xamarin.Form) Plugin.BLE 蓝牙连接

    随着Xamarin.Form项目接近尾声,仔细一算才发现过来大半年时间了. 期间除了刚开始有闲情写写,现在总算有空来总结一下了. 来先说 Plugin.BLE (https://github.com/ ...

  9. 11gR2集群件任务角色分离(Job Role Separation)简介

       从11gR2版本开始,Oracle推荐使用不同的操作系统用户安装GI和数据库软件,例如:使用grid用户安装GI,使用Oracle用户安装数据库软件.当然,用户还是可以使用Oracle用户安装G ...

  10. 1.1 NLP基础技能,字符串的处理

    #!/usr/bin/env python # coding: utf-8 # # 字符串操作 # ### 去空格和特殊字符 # In[8]: s = " hello world! &quo ...