CodeForces 567E President and Roads(最短路 + 双联通分量)

来源:互联网 发布:图像处理区域填充算法 编辑:程序博客网 时间:2024/05/29 23:22

题目链接:http://codeforces.com/problemset/problem/567/E


题意:给出一张有向图,要从起点走到终点,走的是最短路。对于每条边,如果该边是最短路上的必经路,则输出“YES”,如果修改某条边边权可使最短路变短,则输出“CAN X”,X表示最少需要修改的权值,如果修改后的边权会 <= 0,则输出”NO“


思路:先预处理出那些在最短路上的边,判断必经路,则相当于在无向图中找桥,需修改权值用两个dis数组即可算出,注意数据会爆int


#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <utility>#include <cmath>#include <queue>#include <set>#include <map>#include <climits>#include <functional>#include <deque>#include <ctime>#include <string>#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;typedef long long ll;typedef pair <ll, int> P;const int MAXN = 101000;const int MAXM = 500000;const ll INF = 1e17;struct shortestpath{int cnt;int head[MAXN], vis[MAXN];ll dis[MAXN];struct edge{int to, nxt, w;} e[MAXM];void init(){cnt = 0;memset(head, -1, sizeof(head));}void addedge(int u, int v, int w){e[cnt].w = w;e[cnt].to = v;e[cnt].nxt = head[u];head[u] = cnt++;}void dijkstra(int s, int n){memset(vis, 0, sizeof(vis));for (int i = 0; i <= n; i++)dis[i] = INF;priority_queue<P, vector <P>, greater<P> > que;dis[s] = 0;vis[s] = 1;que.push(P(0, s));while (!que.empty()){P p = que.top();que.pop();int u = p.second;if (dis[u] < p.first) continue;for (int i = head[u]; ~i; i = e[i].nxt){if (dis[e[i].to] > dis[u] + e[i].w){dis[e[i].to] = dis[u] + e[i].w;que.push(P(dis[e[i].to], e[i].to));}}}}} Dij1, Dij2;struct Tarjan{int head[MAXN], cnt;int low[MAXN], dfn[MAXN], sta[MAXN], bel[MAXN];bool iscut[MAXN];int top, idx, block, bri;struct edge{int from, to, nxt;bool cut;} e[MAXM];void init(){cnt = 0;memset(head, -1, sizeof(head));}void addedge(int u, int v){e[cnt].from = u;e[cnt].to = v;e[cnt].nxt = head[u];e[cnt].cut = false;head[u] = cnt++;}void tarjan(int u, int pre){int v;low[u] = dfn[u] = ++idx;sta[++top] = u;int child = 0, flag = 1;for (int i = head[u]; ~i; i = e[i].nxt){v = e[i].to;if (flag && v == pre){flag = 0;continue;}if (!dfn[v]){child++;tarjan(v, u);low[u] = min(low[u], low[v]);if (low[v] >= dfn[u]){iscut[u] = true;if (low[v] > dfn[u]){e[i].cut = true;e[i ^ 1].cut = true;}}}elselow[u] = min(low[u], dfn[v]);}if (child == 1 && pre < 0)iscut[u] = false;if (low[u] == dfn[u]){block++;do{bel[sta[top]] = block;}while (sta[top--] != u);}}void solve(int N){idx = top = block = 0;memset(dfn, 0, sizeof(dfn));memset(iscut, 0, sizeof(iscut));memset(bel, -1, sizeof(bel));for (int i = 1; i <= N; i++){if (!dfn[i])tarjan(i, -1);}}} Tar;int vis[MAXM];struct Edge{int u, v, w;} e[MAXN];int main(){int n, m, s, t;while (~scanf("%d%d%d%d", &n, &m, &s, &t)){Dij1.init(), Dij2.init();for (int i = 0; i < m; i++){int u, v, w;scanf("%d%d%d", &u, &v, &w);e[i].u = u, e[i].v = v, e[i].w = w;Dij1.addedge(u, v, w);Dij2.addedge(v, u, w);}Dij1.dijkstra(s, n);Dij2.dijkstra(t, n);// for (int i = 1; i <= n; i++)// printf("*********%I64d %I64d\n", Dij1.dis[i], Dij2.dis[i]);Tar.init();memset(vis, false, sizeof(vis));for (int i = 0; i < m; i++){int u = e[i].u, v = e[i].v, w = e[i].w;if (Dij1.dis[u] + w + Dij2.dis[v] == Dij1.dis[t]){//printf("*****%d %d\n", u, v);Tar.addedge(u, v);Tar.addedge(v, u);vis[i] = Tar.cnt - 1;}}Tar.solve(n);for (int i = 0; i < m; i++){if (vis[i] && Tar.e[vis[i]].cut == true){puts("YES");continue;}int u = e[i].u, v = e[i].v;ll w = Dij1.dis[t] - Dij1.dis[u] - Dij2.dis[v] - 1;if (w <= 0)puts("NO");elseprintf("CAN %I64d\n", e[i].w - w);}}return 0;}


0 0