E. Flawed Flow
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Emuskald considers himself a master of flow algorithms. Now he has completed his most ingenious program yet — it calculates the maximum flow in an undirected graph. The graph consists of n vertices and m edges. Vertices are numbered from 1 to n. Vertices 1 and nbeing the source and the sink respectively.
However, his max-flow algorithm seems to have a little flaw — it only finds the flow volume for each edge, but not its direction. Help him find for each edge the direction of the flow through this edges. Note, that the resulting flow should be correct maximum flow.
More formally. You are given an undirected graph. For each it's undirected edge (ai, bi) you are given the flow volume ci. You should direct all edges in such way that the following conditions hold:
Input
The first line of input contains two space-separated integers n and m (2 ≤ n ≤ 2·105, n - 1 ≤ m ≤ 2·105), the number of vertices and edges in the graph. The following m lines contain three space-separated integers ai, bi and ci (1 ≤ ai, bi ≤ n, ai ≠ bi, 1 ≤ ci ≤ 104), which means that there is an undirected edge from ai to bi with flow volume ci.
It is guaranteed that there are no two edges connecting the same vertices; the given graph is connected; a solution always exists.
Output
Output m lines, each containing one integer di, which should be 0 if the direction of the i-th edge is ai → bi (the flow goes from vertex ai to vertex bi) and should be 1 otherwise. The edges are numbered from 1 to m in the order they are given in the input.
If there are several solutions you can print any of them.
Examples
input
3 3 3 2 10 1 2 10 3 1 5
output
1 0 1
input
4 5 1 2 10 1 3 10 2 3 5 4 2 15 3 4 5
output
0 0 1 1 0
Note
In the first test case, 10 flow units pass through path , and 5 flow units pass directly from source to sink: .
题目大意:
给出N个点,M条无向边(每条边都有流量),我们的任务是将这M条边规定方向,使得:
①1号节点没有入边,
②构建出来的图没有有向环。
③每个点的出流==入流
思路:
题目保证有解,并且结果需要保证1号节点没有入边。
那么我们问题的切入点就在这里。既然保证有解,那么我们写一个类拓扑排序,从节点1出发,然后能够遍历到的点如果in【v】!=一半的流量,那么对应我们就可以将当前边的流量(u,v)加给点v,也就是规定(u,v)这条边的方向不变,相反,如果我们in【v】达到了一半的流量,那么剩余的边就给反向边。
这么做是如何保证结果每个点的入流==出流的呢?难道我们一个点在这样加的过程就不会超过一半流量吗?
仔细想想是一定不会超过的,因为我们从1号节点出发,对应我们到达每个点的流量如果没有达到一半的话,肯定会通过其他边流入进来,如果到达的点有能够达到一半的话,那么拿这个点继续向下去跑,跑出去的流的量肯定是这个点的一半,那么这个点就一定能够满足题目条件,依次类推下去,如果不满足条件的点肯定不会入队,而已经满足了条件的点肯定要入队,入队的点再跑出去的流肯定不用担心入队的点的流量超额,所以整体上这样去做,结果一定是满足条件的。
过程维护一下即可。
Ac代码:
#include#include #include using namespace std; struct node { int from,to,next,w,dir,id; }e[1500000]; int head[350000]; int in[350000]; int out[350000]; int ans[350000]; int n,m,cont; void add(int from,int to,int w,int dir,int id) { e[cont].from=from; e[cont].to=to; e[cont].w=w; e[cont].dir=dir; e[cont].id=id; e[cont].next=head[from]; head[from]=cont++; } void Top() { queue s; s.push(1); in[1]=out[1]=0; while(!s.empty()) { int u=s.front(); s.pop(); for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; int w=e[i].w; int dir=e[i].dir; if(v==1||(in[v]==out[v]&&v!=n))continue; if(u==1||v==n) { if(u==1) { ans[e[i].id]=dir; in[v]+=w; } else { ans[e[i].id]=dir; } } else { if(in[v]!=out[v]) { in[v]+=w; ans[e[i].id]=dir; } else ans[e[i].id]=1-dir; } if(in[v]==out[v]&&v!=n) { s.push(v); } } } for(int i=1;i<=m;i++)printf("%d\n",ans[i]); } int main() { while(~scanf("%d%d",&n,&m)) { cont=0; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++) { int x,y,w;scanf("%d%d%d",&x,&y,&w); add(x,y,w,0,i); add(y,x,w,1,i); out[y]+=w; out[x]+=w; } for(int i=1;i<=n;i++)out[i]=out[i]/2; Top(); } }