省选时孙耀峰大爷讲过传递闭包相关问题,没想到竟然遇上了。
传送门
这题其实可以用孙耀峰大爷论文中“不完全动态传递闭包”,但利用题目中的一些性质会更好。
我一开始的想法是,先将原图scc缩点,对于每一个操作时刻结束后,整个图一定是DAG套树,用静态传递闭包+动态树相关理论即可。因为只有加点,所以可以倍增。
但我们注意到,对于一个询问,如果当前答案为假,那么之后答案也不会为真,因为只有加点,对于原有的点之间并不会加边,所以原先的连通性不会变。利用这个性质,我们只要把所以操作结束后的图做下静态传递闭包就好了。
#include<cctype>
#include<bitset>
#include<cstdio>
#include<vector>
using namespace std;
inline int getint(){
int x=0;
char c=getchar();
while(!isdigit(c))c=getchar();
for(;isdigit(c);c=getchar())x=x*10+c-48;
return x;
}
const int N=50010,M=150010;
struct graph{
int h[N],n,xb;
struct edge{
int to,next;
}e[M];
void init(int n){
this->n=n;
xb=0;
for(int i=1;i<=n;++i)h[i]=0;
}
void addedge(int a,int b){
e[++xb]=(edge){b,h[a]};
h[a]=xb;
}
};
struct DAG:graph{
bitset<N> des[N];
bool b[N];
void dfs(int x){
b[x]=1;
des[x][x]=1;
for(int i=h[x];i;i=e[i].next){
if(!b[e[i].to])dfs(e[i].to);
if(!des[x][e[i].to])des[x]|=des[e[i].to];
}
}
void work(){
for(int i=1;i<=n;++i)des[i].reset(),b[i]=0;
for(int i=1;i<=n;++i)if(!b[i])dfs(i);
}
inline bool is_anc(int u,int v){
return des[u][v];
}
}g1;
struct scc_graph:graph{
int low[N],dfn[N],time,t,s[N],scc_cnt,sccno[N];
vector<int> scc[N];
void dfs(int x){
dfn[s[++t]=x]=low[x]=++time;
for(int i=h[x];i;i=e[i].next)
if(!dfn[e[i].to]){
dfs(e[i].to);
if(low[e[i].to]<low[x])low[x]=low[e[i].to];
}else if(!sccno[e[i].to] && low[e[i].to]<low[x])low[x]=low[e[i].to];
if(low[x]==dfn[x])for(++scc_cnt;s[t+1]!=x;--t)scc[scc_cnt].push_back(s[t]),sccno[s[t]]=scc_cnt;
}
void tarjan(){
time=0;
for(int i=1;i<=n;++i)dfn[i]=low[i]=sccno[i]=0,scc[i].clear();
for(int i=1;i<=n;++i)if(!dfn[i])dfs(i);
}
void rebuild(DAG&g){
for(int i=1;i<=n;++i)
for(int j=h[i];j;j=e[j].next)
if(sccno[i]!=sccno[e[j].to])g.addedge(sccno[i],sccno[e[j].to]);
}
}g;
int n,m,q,i,u,v,q1[M],q2[M],t,x,y;
int main(){
y=n=getint();
g.init(n);
m=getint();
for(i=1;i<=m;++i){
u=getint();
v=getint();
g.addedge(u,v);
}
q=getint();
for(i=1;i<=q;++i){
t=getint();
u=getint();
v=getint();
if(t&1){
if(v)g.addedge(++y,u);
else g.addedge(u,++y);
}else q1[++x]=u,q2[x]=v;
}
g.n=y;
g.tarjan();
g1.init(g.scc_cnt);
g.rebuild(g1);
g1.work();
for(i=1;i<=x;++i)
if(g1.is_anc(g.sccno[q1[i]],g.sccno[q2[i]]))puts("Yes");
else puts("No");
return 0;
}