Sol
注意到 T 想赢必须一步一步缩小 J 的移动空间,所以 T 最优只会移动到割点来缩小 J 的移动空间最终让 J 无处可移。
所以我们考虑建出原图的圆方树。
考虑对于一组询问,把 \(a\) 提起来作为根,那么设 \(b\) 是 \(a\) 的子节点 \(c\) 子树中的节点,那么第一步肯定移动到 \(c\) 的子树中的节点,所以我们只关心在 \(c\) 的子树中是否所有点为 J 的位置时,T 有必胜策略(即可以通过上述方法追到 J)。
你会发现这个显然是可以 dp 的,设 \(dp_{i}\) 表示 J 在以 \(a\) 为全局根,以 \(i\) 为根的子树时,T 是否可以抓到 J,答案是 \(dp_{c}\)。
肯定不能每个询问都提个根跑 dp,可以用一种类似与换根的东西,由于以 \(a\) 作为根的子结点,实际上就是以 \(1\) 作为根 \(a\) 的子结点加上 \(a\) 的父亲(如果有父亲的话),所以再设 \(f_{i}\) 表示 J 在 \(i\) 的子树外的时,T 是否可以抓到 J,具体转移看代码。
这样就只用跑一遍了,时间复杂度 \(O(n \log n)\)。(此处认为 \(n,m,q\) 同阶)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long longinline int read()
{int x(0);char ch(getchar());while(!isdigit(ch))ch=getchar();while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return x;
}const int N=2e5+5;
int n,m,q,ext,dfn[N],low[N],bh[N],siz[N],hvy[N],zg[N],tot,cnt,fa[N],dep[N];
vector<int>nbrg[N],nbrt[N];
set<int>st[N];
bool dp1[N],dp2[N];
stack<int>stk;void Tarjan(int cur)
{dfn[cur]=low[cur]=++tot;stk.push(cur);for(int nxt:nbrg[cur]){if(dfn[nxt]==0){Tarjan(nxt);low[cur]=min(low[cur],low[nxt]);if(low[nxt]==dfn[cur]){ext++;while(stk.top()!=nxt){int x=stk.top();stk.pop();nbrt[x].push_back(ext);nbrt[ext].push_back(x);}stk.pop();nbrt[nxt].push_back(ext);nbrt[ext].push_back(nxt);nbrt[cur].push_back(ext);nbrt[ext].push_back(cur);}}elselow[cur]=min(low[cur],dfn[nxt]);}return ;
}void dfs(int cur,int fa)
{::fa[cur]=fa;dep[cur]=dep[fa]+1;siz[cur]=1;bh[cur]=++cnt;dp1[cur]=true;for(int nxt:nbrt[cur]){if(nxt==fa)continue;dfs(nxt,cur);siz[cur]+=siz[nxt];if(siz[nxt]>siz[hvy[cur]])hvy[cur]=nxt;dp1[cur]&=dp1[nxt];if(cur>n&&!st[fa].count(nxt))dp1[cur]=false;}return ;
}void second_dfs(int cur)
{if(fa[cur]==cur)zg[cur]=zg[fa[cur]];elsezg[cur]=cur;set<int>stt;stt.clear();stt.insert(fa[cur]);int num=0;for(int nxt:nbrt[cur]){if(nxt==fa[cur])continue;stt.insert(nxt);if(dp1[nxt]==false)num++;}for(int nxt:nbrt[cur]){if(nxt==fa[cur])continue;dp2[nxt]=dp2[cur]&&(num==0||(num==1&&dp1[nxt]==false));if(cur>n){int num=1;for(int u:nbrg[nxt])if(stt.count(u))num++;if(num!=(int)stt.size())dp2[nxt]=false;}}for(int nxt:nbrt[cur])if(nxt!=fa[cur])second_dfs(nxt);return ;
}inline int jump(int x,int y)
{while(dep[x]<dep[y]){y=zg[y];if(fa[y]==x)return y;y=fa[y];}return hvy[x];
}signed main()
{ext=n=read(),m=read(),q=read();for(int i=1;i<=m;i++){int x(read()),y(read());st[x].insert(y);st[y].insert(x);nbrg[x].push_back(y);nbrg[y].push_back(x);}Tarjan(1);dfs(1,0);dp2[1]=true;second_dfs(1);for(int i=1;i<=n;i++)if(dp1[i]==true&&dp2[i]==true){while(q--)cout<<"Yes\n";return 0;}while(q--){int a(read()),b(read());if(bh[a]<=bh[b]&&bh[b]<=bh[a]+siz[a]-1){if(dp1[jump(a,b)]==true)cout<<"Yes\n";elsecout<<"No\n";}else if(dp2[a]==true)cout<<"Yes\n";elsecout<<"No\n";}return 0;
}