题解 P2416 【泡芙】

这道题首先需要跑一遍边双连通分量,然后剩下来的就是一颗树,每个点有其点权,询问对于树上一条 ((u,v)) 的简单路径,时候经过的点的点权和不为 (0)

其他题解基本都是跑 (LCA),去求路径的权值,其实这并没有必要,因为两点间的路径点权和为 (0) 的是一个连通块,若询问的 (2) 点在同一个连通块里就说明它们之间路径的点权和为 (0),求连通块可用并查集做,若想得到完美的 (O(n)) 解,则可以 (bfs)

并查集

#include<bits/stdc++.h>
#define log(a) cerr<<"33[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"33[0m"<<endl
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define SZ(x) ((int)x.size()-1)
#define ms(a,b) memset(a,b,sizeof a)
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define DF(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
inline int read(){char ch=getchar(); int w=1,c=0;
	for(;!isdigit(ch);ch=getchar()) if (ch=='-') w=-1;
	for(;isdigit(ch);ch=getchar()) c=(c<<1)+(c<<3)+(ch^48);
	return w*c;
}
const int N=3e5+10;
int n,m,cnt,dfn[N],low[N],sccnum[N],sk[N],tot,scccnt,sccval[N],fa[N];
vector<pair<int,int> >v[N];
vector<int>scctree[N];
void dfs(int x,int fa){
	low[x]=dfn[x]=++cnt;
	sk[tot++]=x;
	for(pair<int,int>i:v[x])
		if(!dfn[i.fi]){
			dfs(i.fi,x);
			low[x]=min(low[x],low[i.fi]);
		}else if(i.fi!=fa){
			low[x]=min(low[x],dfn[i.fi]);
		}
	if(low[x]==dfn[x]){
		scccnt++;
		do{
			sccnum[sk[--tot]]=scccnt;
		}while(sk[tot]!=x);
	}
}
inline int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
int main(){
	n=read(),m=read();
	F(i,1,m){
		int x=read(),y=read(),z=read();
		v[x].pb(mp(y,z));
		v[y].pb(mp(x,z));
	}
	dfs(1,0);
	F(i,1,n)
		for(pair<int,int>j:v[i])
			if(sccnum[i]==sccnum[j.fi])sccval[sccnum[i]]+=j.se;
			else if(!j.se)scctree[sccnum[i]].pb(sccnum[j.fi]);
	F(i,1,scccnt)fa[i]=i;
	F(i,1,scccnt){
	    int l=find(i);
		if(!sccval[i])
			for(int j:scctree[i])
				if(!sccval[j])
					fa[find(j)]=l;
	}
	int q=read();while(q--){
		int s=read(),t=read();
		if(sccval[sccnum[s]]||sccval[sccnum[t]])puts("YES");
		else if(find(sccnum[s])==find(sccnum[t]))puts("NO");
			else puts("YES");
	}
}

(bfs)

#include<bits/stdc++.h>
#define log(a) cerr<<"33[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"33[0m"<<endl
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define SZ(x) ((int)x.size()-1)
#define ms(a,b) memset(a,b,sizeof a)
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define DF(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
inline int read(){char ch=getchar(); int w=1,c=0;
	for(;!isdigit(ch);ch=getchar()) if (ch=='-') w=-1;
	for(;isdigit(ch);ch=getchar()) c=(c<<1)+(c<<3)+(ch^48);
	return w*c;
}
const int N=3e5+10;
int n,m,cnt,dfn[N],low[N],sccnum[N],sk[N],tot,scccnt,sccval[N],block[N];
vector<pair<int,int> >v[N];
vector<int>scctree[N];
void dfs(int x,int fa){
	low[x]=dfn[x]=++cnt;
	sk[tot++]=x;
	for(pair<int,int>i:v[x])
		if(!dfn[i.fi]){
			dfs(i.fi,x);
			low[x]=min(low[x],low[i.fi]);
		}else if(i.fi!=fa){
			low[x]=min(low[x],dfn[i.fi]);
		}
	if(low[x]==dfn[x]){
		scccnt++;
		do{
			sccnum[sk[--tot]]=scccnt;
		}while(sk[tot]!=x);
	}
}
queue<int>q;
int main(){
	n=read(),m=read();
	F(i,1,m){
		int x=read(),y=read(),z=read();
		v[x].pb(mp(y,z));
		v[y].pb(mp(x,z));
	}
	dfs(1,0);
	F(i,1,n)
		for(pair<int,int>j:v[i])
			if(sccnum[i]==sccnum[j.fi])sccval[sccnum[i]]+=j.se;
			else if(!j.se)scctree[sccnum[i]].pb(sccnum[j.fi]);
	F(i,1,scccnt)
		if(!block[i]&&!sccval[i]){
			block[i]=i;
			q.push(i);
			while(q.size()){
				int x=q.front();q.pop();
				for(int j:scctree[x])
					if(!block[j]&&!sccval[j]){
						block[j]=i;
						q.push(j);
					}
			}
		}
	int q=read();while(q--){
		int s=read(),t=read();
		if(!block[sccnum[s]]||!block[sccnum[t]])puts("YES");
		else if(block[sccnum[s]]==block[sccnum[t]])puts("NO");
			else puts("YES");
	}
}

卡常的最优解就不放了

原文地址:https://www.cnblogs.com/zhaohaikun/p/14818902.html