传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4097
从4月份打浙大校赛到这两天对着代码肉眼查错很久还出各种数据调试才该出来,原来还是原来的dfs序判断有问题,当时考场上写的dfs序就是由问题的,还好今天改出来了,不然就要妥协写lca了,其实lca也挺好写的,但我一直坚信dfs序判断巨对所以想把这题调出来。。。。
先边双联通分量缩点,变成一棵树,每条边都是桥,然后从任意一点dfs下去,得到dfs序数组in和out。
我们知道,v,w要到u不经过相同边,及不经过这棵树上的每一条边,于是v,w不能同时是u的父节点的其他分支,不能来自同一儿子节点的子树,不能在森林的不同树上,这样判断就行了。
关于不能来自同一儿子,我们把每个儿子的dfs序排序,然后用lower_bound找看来自第几个儿子,注意此时要按右端点排序,因为儿子节点的dfs序区间都是互不相交的,所以要按右端点比大小,找到大于等于v,w右端点的第一个右端点是哪个儿子。
判断是否来自父节点的其他分支就如果u的dfs序包含在v(w)中或与v(w)的dfs序区间不相交就是了。
上面两个判断一开始没判断全,从4月份WA到现在。。。
#include<bits/stdc++.h>
#define maxl 200010
using namespace std;
int n,m,q,cnt,ccnt,dcc,ind;
int ehead[maxl],in[maxl],out[maxl],c[maxl],f[maxl];
int cehead[maxl];
int dfn[maxl],low[maxl];
struct ed
{
int to,nxt,id;
}e[maxl*2],ce[maxl*2];
struct node
{
int l,r;
bool operator < (const node &b)const
{
return r<b.r;
}
bool operator == (const node &b)const
{
return r==b.r;
}
};
vector <node> cv[maxl];
bool cut[maxl];
inline void add(int u,int v,int id)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];e[cnt].id=id;
ehead[u]=cnt;
}
inline void addc(int u,int v)
{
ce[++ccnt].to=v;ce[ccnt].nxt=cehead[u];
cehead[u]=ccnt;
}
inline void tarjan(int u,int last)
{
dfn[u]=low[u]=++ind;
int v;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(!dfn[v])
{
tarjan(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])
cut[e[i].id]=cut[e[i^1].id]=true;
}
else if(i!=(last^1))
low[u]=min(low[u],dfn[v]);
}
}
inline void dfs(int u)
{
int v;c[u]=dcc;
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(c[v] || cut[e[i].id]) continue;
dfs(v);
}
}
inline int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
inline void cdfs(int u,int fa)
{
in[u]=++ind;
int x=find(u),y,v;
for(int i=cehead[u];i;i=ce[i].nxt)
{
v=ce[i].to;
y=find(v);
if(y!=x)
f[y]=x;
if(v==fa) continue;
cdfs(v,u);
cv[u].push_back(node{in[v],out[v]});
}
sort(cv[u].begin(),cv[u].end());
out[u]=ind;
}
inline void prework()
{
scanf("%d%d%d",&n,&m,&q);
for(register int i=1;i<=n;++i)
ehead[i]=0;
cnt=1;int u,v;
for(register int i=1;i<=m;++i)
{
scanf("%d%d",&u,&v);
add(u,v,i);add(v,u,i);
cut[i]=false;
}
for(register int i=1;i<=n;++i)
dfn[i]=low[i]=c[i]=0;
ind=0;dcc=0;
for(register int i=1;i<=n;++i)
if(!dfn[i])
tarjan(i,0);
for(register int i=1;i<=n;++i)
if(!c[i])
{
++dcc;f[dcc]=dcc;
dfs(i);
in[dcc]=out[dcc]=0;
cehead[dcc]=0;
cv[dcc].clear();
}
ccnt=1;
for(register int i=2;i<=cnt;i+=2)
{
u=e[i].to;v=e[i^1].to;
if(c[u]==c[v]) continue;
addc(c[u],c[v]);addc(c[v],c[u]);
}
ind=0;
for(register int i=1;i<=dcc;++i)
if(!in[i])
cdfs(i,0);
}
inline void mainwork()
{
int u,v,w,id1,id2;bool flag;node d;
for(register int i=1;i<=q;++i)
{
scanf("%d%d%d",&u,&v,&w);
u=c[u];v=c[v];w=c[w];
if(find(u)!=find(v) || find(u)!=find(w))
{
puts("No");
continue;
}
if(u==v || u==w)
{
puts("Yes");
continue;
}
flag=false;
if(in[v]>out[u] || out[v]<in[u] || (in[v]<=in[u] && out[v]>=out[u]))
{
if(in[w]>out[u] || out[w]<in[u] || (in[w]<=in[u] && out[w]>=out[u]))
flag=false;
else
flag=true;
}
else if(in[w]>out[u] || out[w]<in[u] || (in[w]<=in[u] && out[w]>=out[u]))
flag=true;
else
{
d.l=in[v];d.r=out[v];
id1=lower_bound(cv[u].begin(),cv[u].end(),d)-cv[u].begin();
d.l=in[w];d.r=out[w];
id2=lower_bound(cv[u].begin(),cv[u].end(),d)-cv[u].begin();
flag=(id1!=id2);
}
if(flag)
puts("Yes");
else
puts("No");
}
}
inline void print(){}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}
/*
2
6 6 6
1 2
2 3
3 1
4 5
6 4
1 4
4 1 3
1 4 2
1 2 3
1 3 3
4 2 6
2 4 5
2 1 2
1 2
1 1 1
2 1 2
*/