这鸟题真是写吐了。
简单来说就是缩圈后成为一个树,然后就变成询问树上某条路径path[a,b]是否包含某点c。
这里我想屎了,用的主席树,空间卡到死各种改,虽然还是给我搞过去了,但是代码量……其实只要用lca搞一下就ok。
但是,没那么简单,不仅要在缩点后的路径上,还得求出路径在a、b、c、lca块的出、入点。
简单来说就是缩圈后成为一个树,然后就变成询问树上某条路径path[a,b]是否包含某点c。
这里我想屎了,用的主席树,空间卡到死各种改,虽然还是给我搞过去了,但是代码量……其实只要用lca搞一下就ok。
但是,没那么简单,不仅要在缩点后的路径上,还得求出路径在a、b、c、lca块的出、入点。
挺复杂的判断才能判断是否能有一个不重复点的路径。详情见代码吧。长度真是不忍直视。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define NN 100010
struct edge{
int v,ne,g;
}ed[NN*3];
typedef pair<int,int> pii;
vector<pii> he;
int sta[NN],top;
int totb,totdfn,dfn[NN],block[NN],low[NN];
int fi[NN];
bool vis[NN*3];
int te;
int link[NN*5][2];
struct query{
int a,b,c,lca;
}qu[NN];
void init_edge(){
te=-1;
memset(fi,-1,sizeof(fi));
}
void addedge(int fr,int to,int g=0){
++te;ed[te].ne=fi[fr];fi[fr]=te;
ed[te].v=to;ed[te].g=g;
}
void tarjan(int u){
int tmp,e,v;
dfn[u]=low[u]=++totdfn;
sta[++top]=u;
for(e=fi[u];e!=-1;e=ed[e].ne)if (!vis[e]){
v=ed[e].v;
vis[e]=vis[e^1]=1;
if (!dfn[v]){
tarjan(v);
if (low[v]<low[u]) low[u]=low[v];
if (low[v]>dfn[u]){
totb++;
do{
tmp=sta[top--];
block[tmp]=totb;
}while(tmp!=v);
he.push_back(make_pair(u,v));
}
}
else if (dfn[v]<low[u]) low[u]=dfn[v];
}
}
int scc(){
int i,u,v;
memset(dfn,0,sizeof(dfn));
totb=top=totdfn=0;
memset(vis,0,sizeof(vis));
he.clear();
tarjan(1);
if (top){
totb++;
do{
i=sta[top--];
block[i]=totb;
}while(i!=1);
}
init_edge();
for(i=0;i<he.size();++i){
u=he[i].first;v=he[i].second;
addedge(block[u],block[v],u);
addedge(block[v],block[u],v);
}
return totb;
}
vector<pii> vec[NN];
int set[NN];
int findset(int x){return x==set[x]?x:set[x]=findset(set[x]);}
void init_lca(int n){
for(int i=1;i<=n;++i){
vec[i].clear();set[i]=i;vis[i]=0;
}
}
void tarjan_lca(int u,int fa){
int e;
int v;
for(e=fi[u];e!=-1;e=ed[e].ne){
v=ed[e].v;
if (v==fa) continue;
tarjan_lca(v,u);
set[v]=u;
}
vis[u]=1;
for(e=0;e<vec[u].size();++e){
v=vec[u][e].first;
if (vis[v]) qu[vec[u][e].second].lca=findset(v);
}
}
struct segtree{
int ls,rs,w;
}t[NN*20];
int tott;
int root[NN];
int tn;
int build(int l,int r){
int p=++tott;
t[p].w=0;
if (l==r){t[p].ls=t[p].rs=0;return p;}
int m=l+r>>1;
t[p].ls=build(l,m);
t[p].rs=build(m+1,r);
return p;
}
int insert(int pos,int tl,int tr,int pas){
int p=++tott;
t[p]=t[pas];
t[p].w+=1;
if (t[p].ls==t[p].rs){
return p;
}
int m=tl+tr>>1;
if (pos<=m) t[p].ls=insert(pos,tl,m,t[p].ls);
else t[p].rs=insert(pos,m+1,tr,t[p].rs);
return p;
}
int query(int pos,int tl,int tr,int a,int b,int lca){
if (tl==tr){
return t[a].w+t[b].w-2*t[lca].w;
}
int m=tl+tr>>1;
if (pos<=m){
return query(pos,tl,m,t[a].ls,t[b].ls,t[lca].ls);
}
else{
return query(pos,m+1,tr,t[a].rs,t[b].rs,t[lca].rs);
}
}
void dfsbuild(int u,int fa){
root[u]=insert(u,1,tn,root[fa]);
int e,v;
for(e=fi[u];e!=-1;e=ed[e].ne){
v=ed[e].v;
if (v==fa) continue;
dfsbuild(v,u);
}
}
void dfs(int u,int fa,int bg){
int e,v,lca,tmp;
set[u]=-1;
for(e=0;e<vec[u].size();++e){
lca=vec[u][e].first;
tmp=set[lca];
link[vec[u][e].second][0]=tmp;
link[vec[u][e].second][1]=bg;
}
for(e=fi[u];e!=-1;e=ed[e].ne){
v=ed[e].v;
if (v==fa) continue;
set[u]=ed[e].g;
dfs(v,u,ed[e^1].g);
}
set[u]=-1;
}
#define py puts("Yes")
#define pn puts("No")
int main(){
//freopen("4674in.txt","r",stdin);
int n,m,a,b,q,lca,c,i;
int ba,bb,bc;
while(scanf("%d%d",&n,&m)!=EOF){
init_edge();
for(i=1;i<=m;++i){
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
scanf("%d",&q);
for(i=1;i<=q;++i){
scanf("%d%d%d",&a,&b,&c);
qu[i].a=a;
qu[i].b=b;
qu[i].c=c;
}
tn=scc(); //双连通缩点
init_lca(tn); //求lca
for(i=1;i<=q;++i){
a=block[qu[i].a];
b=block[qu[i].b];
vec[a].push_back(make_pair(b,i));
vec[b].push_back(make_pair(a,i));
}
tarjan_lca(1,-1);
he.clear();
for(i=1;i<=tn;++i) vec[i].clear(); //求每个问题中a、b、c的出点
for(i=1;i<=q;++i){
vec[block[qu[i].a]].push_back(make_pair(qu[i].lca,i));
vec[block[qu[i].b]].push_back(make_pair(qu[i].lca,i+q));
vec[block[qu[i].c]].push_back(make_pair(qu[i].lca,i+q*2));
vec[block[qu[i].a]].push_back(make_pair(block[qu[i].c],i+q*3));
vec[block[qu[i].b]].push_back(make_pair(block[qu[i].c],i+q*4));
}
memset(set,-1,sizeof(set));
dfs(1,-1,-1);
for(i=1;i<=tn;++i) vec[i].clear();
tott=-1; //建立主席树
root[0]=build(1,tn);
dfsbuild(1,0);
for(i=1;i<=q;++i){
a=qu[i].a;b=qu[i].b;c=qu[i].c;lca=qu[i].lca;
if (c==b||c==a){py;continue;} //排除c==b、c==a
if (a==b) {pn;continue;} //排除a==b,这样a、b、c肯定不相等了
ba=block[a];bb=block[b];bc=block[c];
if (lca==bc||query(bc,1,tn,root[ba],root[bb],root[lca])) {//首先必须在缩点后的路径上,再判断不合法的
if (lca==ba&&lca==bb){ //a、b、lca同块
if (bc==lca) py;
else pn;
}
else if (lca==ba){ //a与lca同块
if (bc==lca){ //c与lca同块
if (link[i+q][0]!=a) py;
else pn;
}
else if (bc==bb){ //c与b同块
if (link[i+q][1]!=b) py;
else pn;
}
else { //都不同块,则在b->lca路径上
if (link[i+q*2][1]==c) py;
else if (link[i+q*2][1]!=link[i+q*4][0]) py;
else pn;
}
}
else if (lca==bb){ //b与lca同块
if (bc==lca){
if (link[i][0]!=b) py;
else pn;
}
else if (bc==ba){
if (link[i][1]!=a) py;
else pn;
}
else {
if (link[i+q*2][1]==c) py;
else if (link[i+q*2][1]!=link[i+q*3][0]) py;
else pn;
}
}
else { //a、b、lca、都不同块
if (bc==lca){
if (link[i][0]!=link[i+q][0]) py;
else if (link[i][0]==c) py;
else pn;
}
else if (bc==ba){
if (link[i][1]!=a) py;
else pn;
}
else if (bc==bb){
if (link[i+q][1]!=b) py;
else pn;
}
else {
if (link[i+q*2][1]==c) py;
else if (link[i+q*3][0]==-1){
if (link[i+q*4][0]!=link[i+q*2][1]) py;
else pn;
}
else {
if (link[i+q*3][0]!=link[i+q*2][1]) py;
else pn;
}
}
}
}
else pn;
}
}
return 0;
}