【trick&&吐槽】
1,縮環重建圖的時候一定要注意映射關係。
【題意】
有n(3e5)個點,m(3e5)條雙向邊(xi,yi,zi)。
沒有重邊沒有自環(這個條件其實無所謂)
有些邊是特殊的邊(zi==1)
每條邊只能經過一次
問你我們能否有一條路徑,使得我們可以從ST出發到達ED
【類型】
雙連通分量tarjan縮環
BFS
【分析】
這題思考起來有些不著邊際。
關鍵資訊是——一條邊只能經過一次。
什麼情況下一條邊我們會經過多次呢。
經過多次必然形成了環。
於是,介於這個圖是無向圖,我們可以考慮先雙連通縮環。
如果ST和ED在同一個聯通塊內,且這個聯通塊內有special edge 顯然答案為YES
否則的話,已經縮環之後的圖,ST與ED之前肯定只有單一路徑可達,每個點只會入棧一次,被更新一次,於是直接做BFS即可。
就AC啦。
#include <map>#include <stack>#include <queue>#include <deque>#include <cmath>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define L(i) i<<1#define R(i) i<<1|1#define INF 0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-12#define maxn 300100#define MOD 1000000007struct Edge{ int to,next,val;} edge[maxn<<1];int n,m;int tot,head[maxn],scc;int dfn[maxn],low[maxn],time;int sta[maxn],top,S,E,instack[maxn];int belong[maxn],tmp[maxn];vector<pair<int,int> > a[maxn];void init(){ tot = 0; memset(head,-1,sizeof(head));}void add_edge(int u,int v,int cnt){ edge[tot].to = v; edge[tot].val = cnt; edge[tot].next = head[u]; head[u] = tot++;}void tarjan(int u,int pre){ dfn[u] = low[u] = time++; sta[++top] = u; instack[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == pre) continue; if(!dfn[v]) { tarjan(v,u); low[u] = min(low[u],low[v]); } else if(instack[v]) low[u] = min(low[u],dfn[v]); } if(dfn[u] == low[u]) { tmp[++scc] = 0; a[scc].clear(); while(1) { int v = sta[top--]; instack[v] = 0; belong[v] = scc; if(v == u) break; } }}int bfs(){ memset(instack,0,sizeof(instack)); queue<int> q; q.push(belong[S]); instack[belong[S]] = 1; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = a[u].size() - 1; i >= 0; i--) { int v = a[u][i].first; int tp = a[u][i].second; if(instack[v]) continue; tmp[v] |= tmp[u]; tmp[v] |= tp; q.push(v); instack[v] = 1; } } return tmp[belong[E]];}int solve(){ for(int u = 1; u <= n; u++) for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(belong[u] == belong[v]) tmp[belong[u]] |= edge[i].val; a[belong[u]].push_back(make_pair(belong[v],edge[i].val)); } if(belong[S] == belong[E] && tmp[belong[S]]) return 1; return bfs();}int main(){ int t; while(scanf("%d%d",&n,&m) != EOF) { init(); for(int i = 0; i < m; i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add_edge(x,y,z); add_edge(y,x,z); scanf("%d%d",&S,&E); top = 0; time = scc = 0; memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); tarjan(1,0); printf("%s\n",solve()?"YES":"NO"); } } return 0;}