ZOJ 4097 Rescue the Princess(tarjan判桥+LCA)(level 3)

13 篇文章 0 订阅
5 篇文章 0 订阅

题目链接

题意:

给你一个无向图,n个点,m条边,图中可能存在重边,自环

然后有q个询问(n<=1e5,m<=2e5,q<=1e5)

每一次询问u,v,w,问你能不能找到两条路径v->u,w->u

使得两条路径中没有公共的边

有->Yes,无->No

解析:

其实这道题tarjan判桥的特征挺明显的——无向图,重边,自环

然后你画一下样例就可以看出"桥"的存在

然后用tarjan判桥进行缩点,并用找到的割边重新建图,最后会得到一棵树。

剩下的问题就是问你树上z=find(u),x=find(v),y=find(w),从y->w的简单路径中,有没有z

这个问题我是用LCA来做的,

首先y->w的LCA xyl=LCA(xyl,z)   ->z在xyl的子树内

然后z在LCA的路径上  LCA(y,z)==z||LCA(x,z)==z

 

这道题比赛的时候想的有点偏了,没有想到最后成一个树的结构.....

#include<iostream>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include <set>
#include <stack>
using namespace std;

typedef long long ll;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
int findfa(int* fa, int x);
struct edge
{
	int fr, to, nxt;
	int id;


};

edge f[M * 2];
int fa[N];
int now[N];
int head[N];
int fcnt, tim;
int low[N], dfn[N];
int ans[M];
vector<int> mp[N];
int pos[N],Log[N<<2],ST[N<<2][25];
int tot;
int dep[N];
stack<int> ms;

int Min(int x,int y)
{
	return dep[x]<dep[y]?x:y;
}

void dfs(int u,int fc)
{
	ST[++tot][0]=u;
	pos[u]=tot;
	for(int i=0;i<mp[u].size();i++)
	{
		int v=mp[u][i];
		if(v==fc) continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
		ST[++tot][0]=u;
	}
}

void init(int n)
{
	tot=0;
	for(int i=1;i<=n;i++)
	{
		int x=now[i];
		if(!pos[x])
			dep[x]=0,dfs(x,0);
	}

	for(int j=1;j<=Log[n];j++)
		for(int i=1;i<=tot;i++)
		{
			ST[i][j]=Min(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
		}
}

int LCA(int u,int v)
{
	if(u==v) return u;
	u=pos[u];
	v=pos[v];
	if(u>v) swap(u,v);
	int k=Log[v-u+1];
	return Min(ST[u][k],ST[v-(1<<k)+1][k]);
}


void add2(int fr, int to, int id)
{
	f[fcnt].fr = fr;
	f[fcnt].to = to;
	f[fcnt].id = id;
	f[fcnt].nxt = head[fr];
	head[fr] = fcnt++;
}

int findfa(int* fa, int x)
{
	if (x == fa[x]) return fa[x];
	int nex = fa[x];
	fa[x] = findfa(fa, nex);
	return fa[x];
}

void tarjan(int x, int fa)
{
	dfn[x] = low[x] = ++tim;
	ms.push(x);
	for (int i = head[x], to, id; i != -1; i = f[i].nxt)
	{
		if ((id = f[i].id) == fa) continue;
		to = f[i].to;
		if (!dfn[to])
		{
			tarjan(to, id), low[x] = min(low[x], low[to]);
			if (low[to] > dfn[x]) ans[id] = 1;
		}
		else low[x] = min(low[x], dfn[to]);
	}
	if(low[x]==dfn[x])
	{
		int u;
		do
		{
			u=ms.top();
			ms.pop();
			now[u]=x;
		}
		while(u!=x);
	}
}



int main()
{
	int T;
	scanf("%d", &T);
	Log[0]=-1;
	for(int i=1;i<(N<<2);i++) Log[i]=Log[i>>1]+1;

	while (T--)
	{

		fcnt = 0;
		tim = 0;
		int n, m, q;
		scanf("%d%d%d", &n, &m, &q);
		for (int i = 1; i <= n; i++)
		{
			head[i] = -1;
			fa[i] = i;
			low[i] = dfn[i] = 0;
			now[i] = i;
			mp[i].clear();
			pos[i]=dep[i]=0;
			
		}
		for (int i = 1; i <= m; i++)
		{
			ans[i] = 0;
		}
		for (int i = 1; i <= m; i++)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			add2(u, v, i);
			add2(v, u, i);
			int fx = findfa(fa, u);
			int fy = findfa(fa, v);
			if (fx != fy)
			{
				fa[fx] = fy;
			}
		}

		for (int i = 1; i <= n; i++)
		{
			if (!dfn[i]) tarjan(i, -1);
		}
		

		for (int i = 0; i < fcnt; i += 2)
		{
			if (ans[f[i].id])
			{
				int fx =now[f[i].fr];
				int fy = now[f[i].to];
				mp[fx].push_back(fy);
				mp[fy].push_back(fx);
			}

		}
		init(n);
		
		for (int i = 1; i <= q; i++)
		{
			int u, v, w, x, y, z;
			scanf("%d%d%d", &u, &v, &w);
			z = findfa(fa, u);
			x = findfa(fa, v);
			y = findfa(fa, w);
			if (x != z || y != z)
			{
				printf("No\n");
			}
			else
			{
				z = now[u];
				x = now[v];
				y = now[w];
				if (x == y&&z != x)
				{
					printf("No\n");
				}
				else if (x != y&&x != z&&z != y)
				{
					
					int xyl=LCA(x,y);
					int zl=LCA(xyl,z);
					int xz=LCA(x,z);
					int yz=LCA(y,z);
					if(xyl==zl&&(xz==z||yz==z))
						printf("Yes\n");
					else
						printf("No\n");
				}
				else
				{
					printf("Yes\n");
				}
			}

		}

	}
	return 0;
}

这个是在tarjan外面缩点的

#include<iostream>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include <set>
using namespace std;

typedef long long ll;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
int findfa(int* fa, int x);
struct edge
{
	int fr, to, nxt;
	int id;


};

edge f[M * 2];
int fa[N];
int now[N];
int head[N];
int fcnt, tim;
int low[N], dfn[N];
int ans[M];
vector<int> mp[N];
int pos[N],Log[N<<2],ST[N<<2][25];
int tot;
int dep[N];

int Min(int x,int y)
{
	return dep[x]<dep[y]?x:y;
}

void dfs(int u,int fc)
{
	ST[++tot][0]=u;
	pos[u]=tot;
	for(int i=0;i<mp[u].size();i++)
	{
		int v=mp[u][i];
		if(v==fc) continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
		ST[++tot][0]=u;
	}
}

void init(int n)
{
	tot=0;
	for(int i=1;i<=n;i++)
	{
		int x=findfa(now,i);
		if(!pos[x])
			dep[x]=0,dfs(x,0);
	}

	for(int j=1;j<=Log[n];j++)
		for(int i=1;i<=tot;i++)
		{
			ST[i][j]=Min(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
		}
}

int LCA(int u,int v)
{
	if(u==v) return u;
	u=pos[u];
	v=pos[v];
	if(u>v) swap(u,v);
	int k=Log[v-u+1];
	return Min(ST[u][k],ST[v-(1<<k)+1][k]);
}


void add2(int fr, int to, int id)
{
	f[fcnt].fr = fr;
	f[fcnt].to = to;
	f[fcnt].id = id;
	f[fcnt].nxt = head[fr];
	head[fr] = fcnt++;
}

int findfa(int* fa, int x)
{
	if (x == fa[x]) return fa[x];
	int nex = fa[x];
	fa[x] = findfa(fa, nex);
	return fa[x];
}

void tarjan(int x, int fa)
{
	dfn[x] = low[x] = ++tim;
	for (int i = head[x], to, id; i != -1; i = f[i].nxt)
	{
		if ((id = f[i].id) == fa) continue;
		to = f[i].to;
		if (!dfn[to])
		{
			tarjan(to, id), low[x] = min(low[x], low[to]);
			if (low[to] > dfn[x]) ans[id] = 1;
		}
		else low[x] = min(low[x], dfn[to]);
	}
}



int main()
{
	int T;
	scanf("%d", &T);
	Log[0]=-1;
	for(int i=1;i<(N<<2);i++) Log[i]=Log[i>>1]+1;

	while (T--)
	{

		fcnt = 0;
		tim = 0;
		int n, m, q;
		scanf("%d%d%d", &n, &m, &q);
		for (int i = 1; i <= n; i++)
		{
			head[i] = -1;
			fa[i] = i;
			low[i] = dfn[i] = 0;
			now[i] = i;
			mp[i].clear();
			pos[i]=dep[i]=0;
			
		}
		for (int i = 1; i <= m; i++)
		{
			ans[i] = 0;
		}
		for (int i = 1; i <= m; i++)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			add2(u, v, i);
			add2(v, u, i);
			int fx = findfa(fa, u);
			int fy = findfa(fa, v);
			if (fx != fy)
			{
				fa[fx] = fy;
			}
		}

		for (int i = 1; i <= n; i++)
		{
			if (!dfn[i]) tarjan(i, -1);
		}
		for (int i = 0; i < fcnt; i += 2)
		{
			if (ans[f[i].id]) continue;
			int fx = findfa(now, f[i].fr);
			int fy = findfa(now, f[i].to);
			if (fx != fy)
			{
				now[fx] = fy;
			}
		}

		for (int i = 0; i < fcnt; i += 2)
		{
			if (ans[f[i].id])
			{
				int fx = findfa(now, f[i].fr);
				int fy = findfa(now, f[i].to);
				mp[fx].push_back(fy);
				mp[fy].push_back(fx);
			}

		}
		init(n);
		
		for (int i = 1; i <= q; i++)
		{
			int u, v, w, x, y, z;
			scanf("%d%d%d", &u, &v, &w);
			z = findfa(fa, u);
			x = findfa(fa, v);
			y = findfa(fa, w);
			if (x != z || y != z)
			{
				printf("No\n");
			}
			else
			{
				z = findfa(now, u);
				x = findfa(now, v);
				y = findfa(now, w);
				if (x == y&&z != x)
				{
					printf("No\n");
				}
				else if (x != y&&x != z&&z != y)
				{
					/*if(u_in_v(x,y)&&!(u_in_v(z,y)&&u_in_v(x,z)))
						printf("No\n");
					else if(u_in_v(y,x)&&!(u_in_v(z,x)&&u_in_v(y,z)))
						printf("No\n");
					else
						printf("Yes\n");*/
					int xyl=LCA(x,y);
					int zl=LCA(xyl,z);
					int xz=LCA(x,z);
					int yz=LCA(y,z);
					if(xyl==zl&&(xz==z||yz==z))
						printf("Yes\n");
					else
						printf("No\n");
				}
				else
				{
					printf("Yes\n");
				}
			}

		}

	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值