题解 P2416 【泡芙】
这道题首先需要跑一遍边双连通分量,然后剩下来的就是一颗树,每个点有其点权,询问对于树上一条 \((u,v)\) 的简单路径,时候经过的点的点权和不为 \(0\)。
其他题解基本都是跑 \(LCA\),去求路径的权值,其实这并没有必要,因为两点间的路径点权和为 \(0\) 的是一个连通块,若询问的 \(2\) 点在同一个连通块里就说明它们之间路径的点权和为 \(0\),求连通块可用并查集做,若想得到完美的 \(O(n)\) 解,则可以 \(bfs\)。
并查集
#include
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<=(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 >v[N];
vectorscctree[N];
void dfs(int x,int fa){
low[x]=dfn[x]=++cnt;
sk[tot++]=x;
for(pairi: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(pairj: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
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<=(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 >v[N];
vectorscctree[N];
void dfs(int x,int fa){
low[x]=dfn[x]=++cnt;
sk[tot++]=x;
for(pairi: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);
}
}
queueq;
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(pairj: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");
}
}
卡常的最优解就不放了