1. 程式人生 > 實用技巧 >萬用字元與特殊符號

萬用字元與特殊符號

題解:問a,b之間是否有z=1的邊,其實就是找一下邊雙連通分量,縮點後重新建圖,變成了一棵樹,詢問a,b之間的邊權和是否>0。
可以直接從a開始spfa找一下最長路,看看是否有dis[b]>0

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

const int N=3e5+10;
int read()
{
	int x=0,f=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int n,m;
int head[N],pos;
struct edge{
	int fr,to,next,w;
}e[N<<1],E[N<<1];
void add(int x,int y,int z)
{
	e[++pos].next=head[x];
	e[pos].fr=x;
	e[pos].to=y;
	e[pos].w=z;
	head[x]=pos;
}
int head1[N],ppos;
void add1(int x,int y,int z)
{
	E[++ppos].next=head1[x];
	E[ppos].fr=x;
	E[ppos].to=y;
	E[ppos].w=z;
	head1[x]=ppos;
}
int dfn[N],low[N],st[N],top,cnt,bel[N],bcc,ins[N];
void tarjan(int u,int f)
{
	dfn[u]=low[u]=++cnt;
	st[++top]=u;//ins[u]=1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;if(v==f)continue;
		if(!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		bcc++;
		while(st[top]!=u)
		{
			//ins[st[top]]=0;
			bel[st[top--]]=bcc;
		}
		//ins[st[top]]=0;
		bel[st[top--]]=bcc;
	}
}
int w[N];
void build()
{
	for(int i=1;i<=pos;i+=2)
	{
		int fr=e[i].fr,to=e[i].to;
		if(bel[fr]==bel[to]&&e[i].w==1) w[bel[fr]]=1;
		else if(bel[fr]!=bel[to])
			add1(bel[fr],bel[to],e[i].w),add1(bel[to],bel[fr],e[i].w);
	}
}
queue<int> q;
int vis[N],dis[N];
int query(int x,int y)
{
	q.push(x);vis[x]=1;dis[x]=w[x];
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=head1[u];i;i=E[i].next)
		{
			int v=E[i].to;if(vis[v])continue;
			if(dis[v]<dis[u]+E[i].w+w[v])
				dis[v]=dis[u]+E[i].w+w[v];
			q.push(v);vis[v]=1;
		}
	}
	return dis[y];
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read(),z=read();
		add(x,y,z);add(y,x,z);
	}
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);
	build();
	int a,b;
	scanf("%d%d",&a,&b);
	if(query(bel[a],bel[b])!=0) puts("YES");else puts("NO");
	return 0;
}