Description
给出一个n个点,m条边的无向图。你要确定每一条边的方向,使得所有q个要求(s,t)都能从s出发到达t。
输出是否能完成所有要求。
n,m,q<=2*10^5
Solution
显然,对于同一个点双里面的点,都是至少有两种方法可达的。
也就是双联通缩点喽~
然后缩完点就是棵数。
Nlog2N
用两个方向的链剖维护,线段树打上标记,判断是否冲突
NlogN
其实可以离线,然后给每个向上的边打上标记,向下的也打上标记。
然后在lca那里把标记消掉。
(树上的线段覆盖)
N
都离线了lca就用tarjan嘛。。。
51nod有毒,要求竟然不在同一个联通块内!!
CF首题纪念
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 200005
using namespace std;
int n,m,q,tot,id,cnt,l,u,v;
int dfn[N],low[N],d[N],c[N],x[N],y[N],f[N],g[N],fa[N][18],dep[N],belong[N];
int last[N],next[N*2],t[N*2];
bool in[N],bz[N*2];
void add(int x,int y) {
t[++l]=y;next[l]=last[x];last[x]=l;
}
void tarjan(int x) {
dfn[x]=low[x]=++tot;d[tot]=x;in[x]=1;belong[x]=cnt;
rep(i,x) if (!bz[i]) {
if (!dfn[t[i]]) {
bz[i]=bz[i^1]=1;tarjan(t[i]);
low[x]=min(low[x],low[t[i]]);
} else if (in[t[i]]) low[x]=min(low[x],dfn[t[i]]);
}
if (low[x]==dfn[x]) {
id++;
while (d[tot+1]!=x) c[d[tot]]=id,in[d[tot--]]=0;
}
}
void dfs(int x,int y) {
dep[x]=dep[y]+1;fa[x][0]=y;bz[x]=1;
rep(i,x) if (t[i]!=y) dfs(t[i],x);
}
void get(int x) {
bz[x]=1;
rep(i,x) if (t[i]!=fa[x][0]) {
get(t[i]);
f[x]+=f[t[i]];
g[x]+=g[t[i]];
}
}
int lca(int x,int y) {
if (dep[x]<dep[y]) swap(x,y);
fd(j,17,0) if (dep[fa[x][j]]>dep[y]) x=fa[x][j];
if (dep[x]!=dep[y]) x=fa[x][0];
fd(j,17,0) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
if (x!=y) return fa[x][0]; else return x;
}
int main() {
scanf("%d%d%d",&n,&m,&q);l=1;
fo(i,1,m) scanf("%d%d",&x[i],&y[i]),add(x[i],y[i]),add(y[i],x[i]);
fo(i,1,n) if (!dfn[i]) cnt++,tarjan(i);
memset(last,0,sizeof(last));l=0;memset(bz,0,sizeof(bz));
fo(i,1,m) if (c[x[i]]!=c[y[i]]) add(c[x[i]],c[y[i]]),add(c[y[i]],c[x[i]]);
fo(i,1,id) if (!bz[i]) dfs(i,0);memset(bz,0,sizeof(bz));
fo(j,1,17) fo(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];
for(;q;q--) {
scanf("%d%d",&u,&v);
if (belong[u]!=belong[v]) {printf("No");return 0;}
u=c[u];v=c[v];
int z=lca(u,v);
f[u]++;f[z]--;g[v]++;g[z]--;
}
fo(i,1,id) if (!bz[i]) get(i);bool pd=0;
fo(i,1,id) if (f[i]&&g[i]) pd=1;
if (pd) printf("No");else printf("Yes");
}