[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;
}
posted @ 2023-02-04 17:49  PYWBKTDA  阅读(85)  评论(0编辑  收藏  举报