<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

176. Flow construction
time limit per test: 0.5 sec.
memory limit per test: 4096 KB
input: standard
output: standard



You have given the net consisting of nodes and pipes; pipes connect the nodes. Some substance can flow by pipes, and flow speed in any pipe doesn't exceed capacity of this pipe.
The substance cannot be accumulated in the nodes. But it is being produced in the first node with the non-negative speed and being consumed with the same speed in the last node.
You have some subset taken from the set of pipes of this net. You need to start the motion of substance in the net, and your motion must fully fill the pipes of the given subset. Speed of the producing substance in the first node must be minimal.
Calculate this speed and show the scene of substance motion.
Remember that substance can't be accumulated in the nodes of the net.

Input
Two positive integer numbers N (1<=N<=100) and M have been written in the first line of the input - numbers of nodes and pipes.
There are M lines follows: each line contains four integer numbers Ui, Vi, Zi, Ci; the numbers are separated by a space. Ui is the beginning of i-th pipe, Vi is its end, Zi is a capacity of i-th pipe (1<=Zi<=10^5) and Ci is 1 if i-th pipe must be fully filled, and 0 otherwise.
Any pair of nodes can be connected only by one pipe. If there is a pipe from node A to node B, then there is no pipe from B to A. Not a single node is connected with itself.
There is no pipe which connects nodes number 1 and N. Substance can flow only from the beginning of a pipe to its end.

Output
Write one integer number in the first line of the output - it ought to be the minimal speed of the producing substance in the first node.
Write M integers in the second line - i-th number ought to be the flow speed in the i-th pipe (numbering of pipes is equal to the input).
If it is impossible to fill the given subset, write "Impossible".

Sample test(s)

Input
Input 1:
4 4
1 2 2 0
2 4 1 1
1 3 2 1
3 4 3 0
Input 2:
4 4
1 2 1 0
2 4 2 1
1 3 3 1
3 4 2 0

Output
Output 1:
3
1 1 2 2
Output 2:
Impossible
Author:	Dmitry Orlov
Resource:	Saratov ST team Spring Contest #1
Date:	18.05.2003

<|response|>
1. Abridged problem statement  
You have a directed graph of N nodes (numbered 1…N) and M pipes. Pipe i goes from Ui to Vi, has capacity Zi, and a flag Ci:  
- If Ci=1, you must send exactly Zi units of flow through that pipe (lower bound = Zi).  
- If Ci=0, you can send any flow in [0, Zi].  

You produce flow at node 1 at rate X≥0, consume it at node N at the same rate X, and every intermediate node must satisfy flow conservation (no storage). Find the minimal X for which a feasible flow exists meeting all lower‐bound requirements, and output X and the flow on each pipe. If no such X exists, print “Impossible.”

2. Key observations  
1. Pipes with Ci=1 impose a lower bound on flow; those with Ci=0 have lower bound 0.  
2. A flow with lower bounds can be reduced to a circulation problem by:  
   - Replacing each edge’s capacity from [lb, ub] to [0, ub−lb].  
   - Recording at each node a “demand” equal to (sum of incoming lbs) − (sum of outgoing lbs).  
3. To allow net injection of X at node 1 and removal at node N, add an extra edge N→1 with capacity X and lower bound 0.  
4. A feasible circulation with these transformed edges exists if and only if, after adding a super‐source S connected to all demand‐positive nodes and a super‐sink T connected from all demand‐negative nodes, the max flow S→T saturates all demand edges.  
5. Since X is unknown, we can binary‐search X and test feasibility by running a max‐flow for each candidate X.

3. Full solution approach  
1. Parse input, convert to 0-based indices. For each pipe i, set lb[i] = (Ci? Zi : 0), ub[i] = Zi.  
2. Define a function feasible(X):  
   a. Initialize demand[0…N−1] = 0.  
   b. Create a flow network of size N+2 (nodes 0…N−1 are original, node N=super-source S, node N+1=super-sink T).  
   c. For each original pipe i from u→v:  
      - demand[u] −= lb[i];  demand[v] += lb[i].  
      - Add edge u→v with capacity (ub[i]−lb[i]) and remember its index=i.  
   d. For each node i in [0…N−1]:  
      - If demand[i]>0, add edge S→i with capacity demand[i].  
      - If demand[i]<0, add edge i→T with capacity −demand[i].  
   e. Add edge (N−1)→0 with capacity X (the “circulation creator”).  
   f. Compute max‐flow from S to T. Let totalDemand = sum of all demand[i]>0. If max-flow == totalDemand, return true; else false.  
3. Binary‐search X over [0…sum_of_all_Zi] (or up to 1e8). If no X is feasible, print “Impossible.” Otherwise let X* be the minimal feasible X.  
4. Rebuild the network for X*, run one more max‐flow to get the flow values on the transformed edges. For each original pipe i, its actual flow = (flow on transformed edge i) + lb[i].  
5. Output X* and the M flows in input order.

4. C++ implementation
```cpp
#include <bits/stdc++.h>
// #include <coding_library/graph/maxflow.hpp>

using namespace std;

template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

template<class T>
class MaxFlow {
  private:
    const static T INF = numeric_limits<T>::max();

    struct Edge {
        T flow, cap;
        int idx, rev, to;
        Edge(int _to, int _rev, T _flow, T _cap, int _idx)
            : to(_to), rev(_rev), flow(_flow), cap(_cap), idx(_idx) {}
    };

    vector<int> dist, po;
    int n;

    bool bfs(int s, int t) {
        fill(dist.begin(), dist.end(), -1);
        fill(po.begin(), po.end(), 0);

        queue<int> q;
        q.push(s);
        dist[s] = 0;

        while(!q.empty()) {
            int u = q.front();
            q.pop();

            for(Edge e: adj[u]) {
                if(dist[e.to] == -1 && e.flow < e.cap) {
                    dist[e.to] = dist[u] + 1;
                    q.push(e.to);
                }
            }
        }
        return dist[t] != -1;
    }

    T dfs(int u, int t, T fl = INF) {
        if(u == t) {
            return fl;
        }

        for(; po[u] < (int)adj[u].size(); po[u]++) {
            auto& e = adj[u][po[u]];
            if(dist[e.to] == dist[u] + 1 && e.flow < e.cap) {
                T f = dfs(e.to, t, min(fl, e.cap - e.flow));
                e.flow += f;
                adj[e.to][e.rev].flow -= f;
                if(f > 0) {
                    return f;
                }
            }
        }

        return 0;
    }

  public:
    MaxFlow(int n = 0) { init(n); }

    vector<vector<Edge>> adj;

    void init(int _n) {
        n = _n;
        adj.assign(n + 1, {});
        dist.resize(n + 1);
        po.resize(n + 1);
    }

    void add_edge(int u, int v, T w, int idx = -1) {
        adj[u].push_back(Edge(v, adj[v].size(), 0, w, idx));
        adj[v].push_back(Edge(u, adj[u].size() - 1, 0, 0, -1));
    }

    T flow(int s, int t) {
        assert(s != t);

        T ret = 0, to_add;
        while(bfs(s, t)) {
            while((to_add = dfs(s, t))) {
                ret += to_add;
            }
        }

        return ret;
    }
};

int n, m;
vector<tuple<int, int, int, int>> edges;

void read() {
    cin >> n >> m;
    edges.resize(m);
    for(int i = 0; i < m; i++) {
        int u, v, cap, flag;
        cin >> u >> v >> cap >> flag;
        u--, v--;
        edges[i] = {u, v, cap, flag ? cap : 0};
    }
}

pair<vector<int>, MaxFlow<int>> build_circulation(int x) {
    MaxFlow<int> mf(n + 2);

    vector<int> deg(n);
    for(int i = 0; i < m; i++) {
        auto [u, v, cap, lb] = edges[i];
        deg[v] += lb;
        deg[u] -= lb;
        mf.add_edge(u, v, cap - lb, i);
    }

    for(int i = 0; i < n; i++) {
        if(deg[i] > 0) {
            mf.add_edge(n, i, deg[i]);
        } else if(deg[i] < 0) {
            mf.add_edge(i, n + 1, -deg[i]);
        }
    }

    mf.add_edge(n - 1, 0, x);
    return {deg, mf};
}

bool check_circulation(int x) {
    auto [deg, mf] = build_circulation(x);
    int need_flow = 0;
    for(int i = 0; i < n; i++) {
        if(deg[i] > 0) {
            need_flow += deg[i];
        }
    }

    return mf.flow(n, n + 1) == need_flow;
}

void solve() {
    // Minimum-source flow with lower bounds. Edges marked Ci = 1 must be fully
    // filled, so they have lower bound = upper bound = capacity; the rest have
    // lower bound 0. We binary search on the source production speed x: add a
    // back edge from node N-1 to node 0 with capacity x to turn the s-t flow
    // into a circulation, reduce the lower bounds in the standard way (each
    // edge u->v with lower bound lb contributes deg[v] += lb, deg[u] -= lb and
    // a residual edge of capacity cap - lb), and add a super source/sink that
    // supplies/drains the excess. A feasible circulation exists for a given x
    // iff the super-source-to-super-sink max flow saturates all positive
    // demands. We take the smallest feasible x, then read the actual per-pipe
    // flow as lower bound plus residual flow.

    int low = 0, high = (int)1e8, mid, ans = -1;
    while(low <= high) {
        mid = (low + high) / 2;
        if(check_circulation(mid)) {
            ans = mid;
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }

    if(ans == -1) {
        cout << "Impossible\n";
    } else {
        MaxFlow<int> mf = build_circulation(ans).second;
        mf.flow(n, n + 1);

        cout << ans << '\n';
        vector<int> flow(m);
        for(int u = 0; u < n; u++) {
            for(auto e: mf.adj[u]) {
                if(e.idx != -1) {
                    flow[e.idx] = e.flow + get<3>(edges[e.idx]);
                }
            }
        }

        cout << flow << '\n';
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        // cout << "Case #" << test << ": ";
        solve();
    }

    return 0;
}
```

5. Python implementation with detailed comments  
```python
import sys
from collections import deque

class Dinic:
    def __init__(self, n):
        self.n = n
        self.adj = [[] for _ in range(n)]
        self.level = [0]*n
        self.ptr = [0]*n

    def add_edge(self, u, v, c, idx=-1):
        # forward edge: [to, cap, flow, rev_index, orig_idx]
        self.adj[u].append([v, c, 0, len(self.adj[v]), idx])
        # reverse edge
        self.adj[v].append([u, 0, 0, len(self.adj[u]) - 1, -1])

    def bfs(self, S, T):
        for i in range(self.n):
            self.level[i] = -1
        q = deque([S])
        self.level[S] = 0
        while q:
            u = q.popleft()
            for v, cap, flow, rev, _ in self.adj[u]:
                if self.level[v] < 0 and flow < cap:
                    self.level[v] = self.level[u] + 1
                    q.append(v)
        return self.level[T] >= 0

    def dfs(self, u, T, pushed):
        if pushed == 0 or u == T:
            return pushed
        for cid in range(self.ptr[u], len(self.adj[u])):
            v, cap, flow, rev, _ = self.adj[u][cid]
            if self.level[v] == self.level[u] + 1 and flow < cap:
                tr = self.dfs(v, T, min(pushed, cap-flow))
                if tr > 0:
                    self.adj[u][cid][2] += tr
                    self.adj[v][rev][2] -= tr
                    return tr
            self.ptr[u] += 1
        return 0

    def max_flow(self, S, T):
        flow = 0
        INF = 10**18
        while self.bfs(S, T):
            self.ptr = [0]*self.n
            while True:
                pushed = self.dfs(S, T, INF)
                if not pushed:
                    break
                flow += pushed
        return flow

def build_graph(N, pipes, X):
    S, T = N, N+1
    mf = Dinic(N+2)
    demand = [0]*N

    # 1) adjust for lower bounds
    for i, (u, v, cap, lb) in enumerate(pipes):
        demand[u] -= lb
        demand[v] += lb
        mf.add_edge(u, v, cap-lb, i)

    # 2) super‐source/sink for demands
    total_demand = 0
    for i in range(N):
        if demand[i] > 0:
            mf.add_edge(S, i, demand[i])
            total_demand += demand[i]
        elif demand[i] < 0:
            mf.add_edge(i, T, -demand[i])

    # 3) circulation‐creator edge N-1 → 0
    mf.add_edge(N-1, 0, X)
    return mf, total_demand

def feasible(N, pipes, X):
    mf, need = build_graph(N, pipes, X)
    got = mf.max_flow(N, N+1)
    return got == need

def main():
    input = sys.stdin.readline
    N, M = map(int, input().split())
    pipes = []
    for _ in range(M):
        u, v, z, c = map(int, input().split())
        u -= 1; v -= 1
        lb = z if c == 1 else 0
        pipes.append((u, v, z, lb))

    # binary search on X
    lo, hi, ans = 0, 10**8, -1
    while lo <= hi:
        mid = (lo + hi)//2
        if feasible(N, pipes, mid):
            ans = mid
            hi = mid - 1
        else:
            lo = mid + 1

    if ans < 0:
        print("Impossible")
        return

    # rebuild for ans, run flow, extract flows
    mf, _ = build_graph(N, pipes, ans)
    mf.max_flow(N, N+1)
    res = [0]*M
    for u in range(N):
        for v, cap, flow, rev, idx in mf.adj[u]:
            if idx >= 0:
                # actual flow = recorded flow + lb
                res[idx] = flow + pipes[idx][3]

    print(ans)
    print(*res)

if __name__ == "__main__":
    main()
```