题意:
给你一个无向图,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;
}