[树上差分][dfs] Luogu P4652 One-Way Streets
题目描述
给定一张 nn 个点 mm 条边的无向图,现在想要把这张图定向。
有 pp 个限制条件,每个条件形如 (x_i,y_i)(xi,yi),表示在新的有向图当中,x_ixi 要能够沿着一些边走到 y_iyi。
现在请你求出,每条边的方向是否能够唯一确定。同时请给出这些能够唯一确定的边的方向。
题解
- 我们很容易发现,如果我i们加了一条边后,如果出现了环,这上面的边全是B
- 然后我们考虑L和R怎么判,很明显,在判完B之后,剩下的都是无环的
- 因为不会出现说方向不同的两条目标路
- 这启发我们可以使用一个树上差分,然后就知道一条边的指向了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 const int N=100010; 7 int n,m,p,cnt,head[N],f2[N],f1[N]; 8 struct edge { int x,y,from,id; }e[N*2]; 9 void init (int x,int y,int z) { e[++cnt].x=x,e[cnt].y=y,e[cnt].id=z,e[cnt].from=head[x],head[x]=cnt; } 10 bool vis[N],vis1[N<<1]; 11 char ans[N]; 12 void dfs (int x) 13 { 14 vis[x]=true; 15 for (int i=head[x];i!=-1;i=e[i].from) 16 { 17 int y=e[i].y; 18 if (!vis[y]) vis1[e[i].id]=true,dfs(y); 19 else if (!vis1[e[i].id]) ans[e[i].id]='B',vis1[e[i].id]=true,f1[x]++,f1[y]--; 20 } 21 } 22 void dfs1 (int x) 23 { 24 vis[x]=true; 25 for (int i=head[x];i!=-1;i=e[i].from) 26 if (!vis[e[i].y]) 27 { 28 int y=e[i].y; dfs1(y); 29 if (f1[y]>0) ans[e[i].id]='B'; 30 else if ((f2[y]>0&&(i&1))||(f2[y]<0&&(!(i&1)))) ans[e[i].id]='L'; 31 else if ((f2[y]<0&&(i&1))||(f2[y]>0&&(!(i&1)))) ans[e[i].id]='R'; 32 f1[x]+=f1[y];f2[x]+=f2[y]; 33 } 34 } 35 int main() 36 { 37 scanf("%d%d",&n,&m),memset(head,-1,sizeof(head)); 38 for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),init(x,y,i),init(y,x,i); 39 scanf("%d",&p); 40 for (int i=1,x,y;i<=p;i++) scanf("%d%d",&x,&y),f2[x]++,f2[y]--; 41 memset(vis,false,sizeof(vis)),memset(vis1,false,sizeof(vis1)); 42 for (int i=1;i<=n;i++) if (!vis[i]) dfs(i); 43 memset(vis,false,sizeof(vis)); 44 for (int i=1;i<=n;i++) if (!vis[i]) dfs1(i); 45 for (int i=1;i<=m;i++) if (!ans[i]) printf("B"); else printf("%c",ans[i]); 46 }