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

題目鏈接

題意:

給你一個無向圖,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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章