[loj3806]放学路
新建一条边\((1,n,L)\),则\(1\)和\(n\)在一个点双内,且该点双外的点均不会被经过
在此基础上,考虑以下三种情况:
- 对于度数\(\le 1\)的点(除\(1,n\)外),同样不会被经过,不妨删除
- 对于度数\(=2\)的点(除\(1,n\)外),将对应两边合并(边权和相加,标记取或)
- 对于重边,若边权相同直接合并,否则该边即严格长于最短路,将其标记
重复上述过程,若最终仅包含\(1\)和\(n\)之间的边且未被标记即无解
结论:若不为上述情况,则必然有解
(以下仅仅是口胡,并不完全严谨)
根据点双,存在\(1\)到\(n\)的两条路径,并分类讨论:
若两条路径之间存在边,借助该边即可构造路径
若边均在某条路径内部,由于度数\(\ge 3\)的性质,总存在两条边有交
此时,走第一条并沿着中间返回后走第二条即可
边集用set维护即可,时间复杂度为\(O(n+m\log m)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100005;
int n,m,x,y,z,st[N],dfn[N],low[N],vis[N];
ll d[N];queue<int>q;vector<int>v,e[N];
set<int>S[N];unordered_map<int,ll>w[N];
void add(int x,int y,ll z){
if (w[x].find(y)==w[x].end())w[x][y]=z;
if (w[x][y]!=z)w[x][y]=-1;
}
void dfs(int k,int fa){
st[++st[0]]=k;
dfn[k]=low[k]=++dfn[0];
for(int i:e[k])
if (i!=fa){
if (dfn[i])low[k]=min(low[k],dfn[i]);
else{
dfs(i,k),low[k]=min(low[k],low[i]);
if (dfn[k]<=low[i]){
bool flag=0;
v.clear();
while (st[st[0]]!=i){
if (st[st[0]]==n)flag=1;
v.push_back(st[st[0]--]);
}
if (st[st[0]]==n)flag=1;
v.push_back(st[st[0]--]);
if ((k==1)&&(flag)){
vis[1]=1;
for(int j:v)vis[j]=1;
}
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
e[x].push_back(y);
e[y].push_back(x);
add(x,y,z),add(y,x,z);
}
e[1].push_back(n);
e[n].push_back(1);
memset(vis,0,sizeof(vis));
dfs(1,0);
for(int i=1;i<=n;i++)
for(int j:e[i])
if ((vis[i])&&(vis[j]))S[i].insert(j);
memset(vis,0,sizeof(vis));
for(int i=2;i<n;i++)
if (S[i].size()<=2)q.push(i);
while (!q.empty()){
int k=q.front();q.pop();
if (vis[k])continue;
vis[k]=1;
if (S[k].empty())continue;
int x=(*S[k].begin());
if (S[k].size()==1){
S[x].erase(k);
if ((x!=1)&&(x!=n)&&(S[x].size()<=2))q.push(x);
}
if (S[k].size()==2){
int y=(*--S[k].end());
S[x].erase(k),S[y].erase(k);
ll W=((w[k][x]<0)||(w[k][y]<0) ? -1 : w[k][x]+w[k][y]);
add(x,y,W),add(y,x,W);
S[x].insert(y),S[y].insert(x);
if ((x!=1)&&(x!=n)&&(S[x].size()<=2))q.push(x);
if ((y!=1)&&(y!=n)&&(S[y].size()<=2))q.push(y);
}
}
for(int i=2;i<n;i++)
if (!vis[i]){
puts("1");
return 0;
}
if (w[1][n]<0)puts("1");
else puts("0");
return 0;
}