import java.util.*; import java.io.*; public class lodge_font { public static void main(String[] args) throws Exception { PrintWriter out = new PrintWriter(System.out); new lodge_font(new FastScanner(System.in), out); out.close(); } Graph fwd; int[] order; Reachability reach; DynamicLCA dom_tree; // Return the LCA of k nodes int groupLCA(int ... group) { int lca = group[0]; for (int i : group) lca = dom_tree.lca(lca, i); return lca; } long disperse(int i, int k, int[] group, int[] sub, int[] subgroup, int[] limit) { if (i == subgroup.length) return k == 0 ? 1L : 0; // Gather all the nodes from group (i) together in one thing int sz = 0; for (int s : sub) if (s == subgroup[i]) sz++; int[] newGroup = new int[sz]; sz = 0; for (int x=0; x subtreeIDs = new TreeSet<>(); int[] sub = new int[group.length]; for (int v : group) { int dd = dom_tree.depth[v]-dom_tree.depth[root]-1; int rr = dom_tree.walk(v, dd); subtreeIDs.add(rr); sub[ptr++] = rr; } if (subtreeIDs.size() > k) return 0; // Try dispersing the remaining stuff ptr = 0; int[] subgroups = new int[subtreeIDs.size()]; for (int v : subtreeIDs) subgroups[ptr++] = v; for (int i=0; i order[subgroups[j]]) { int tmp = subgroups[i]; subgroups[i] = subgroups[j]; subgroups[j] = tmp; } return disperse(0, k, group, sub, subgroups, limitNodes); } // Find how many choices we have for this branch int countAllowed(int top, int pos, int[] limits) { int curd = dom_tree.depth[pos] - dom_tree.depth[top], res = 0; if (curd > 0) { int start = Integer.numberOfTrailingZeros(Integer.highestOneBit(curd)); for (int d=start; d>=0; d--) { int mm = 1<0) { int i = in.nextInt()-1; int j = in.nextInt()-1; fwd.add(i, j); indeg[j]++; } Graph rev = fwd.reverse(); dom_tree = new DynamicLCA(N); reach = new Reachability(fwd, rev); int topCounter = 0; order = new int[N]; Arrays.fill(order, -1); ArrayDeque q = new ArrayDeque<>(); q.add(0); if (indeg[0] != 0) { System.out.println("SRC not free"); return; } while (q.size() > 0) { int i = q.poll(); order[i] = topCounter++; if (rev.adj[i].size() > 0) { int lca = rev.adj[i].get(0); for (int j : rev.adj[i]) lca = dom_tree.lca(lca, j); dom_tree.add(lca, i); } for (int j : fwd.adj[i]) { indeg[j]--; if (indeg[j] == 0) q.add(j); } } // Safety data check for (int i=0; i0) { int K = in.nextInt(); int numCabins = in.nextInt(); int[] cabins = new int[numCabins]; for (int i=0; i q; boolean[][] canHit, canHitR; Reachability(Graph ff, Graph rr) { fwd=ff; rev=rr; // Construct a directed spanning tree with LCA // For each edge i->j not in ST keep track of i TreeSet heads = new TreeSet<>(); boolean[] seen = new boolean[fwd.N]; q = new ArrayDeque<>(); st = new DynamicLCA(fwd.N); q.add(0); while (q.size() > 0) { int i = q.poll(); for (int j : fwd.adj[i]) { if (seen[j]) heads.add(i); else { seen[j] = true; st.add(i, j); q.add(j); } } } int ptr = 0; hitSrcs = new int[heads.size()]; for (int i : heads) hitSrcs[ptr++] = i; canHit = construct(fwd); canHitR = construct(rev); } // Constructs a reachability graph for key nodes boolean[][] construct(Graph g) { boolean[][] seen = new boolean[hitSrcs.length][g.N]; for (int x=0; x 0) { int i = q.poll(); for (int j : g.adj[i]) if (!seen[x][j]) { seen[x][j] = true; q.add(j); } } } return seen; } // For testing purposes boolean slowReach(int src, int dst) { boolean[] seen = new boolean[fwd.N]; q.add(src); seen[src] = true; while (q.size() > 0) { int i = q.poll(); for (int j : fwd.adj[i]) if (!seen[j]) { seen[j] = true; q.add(j); } } return seen[dst]; } // Fast version boolean canReach(int i, int j) { // Check the spanning tree first if (st.depth[i] <= st.depth[j]) { int k = st.walk(j, st.depth[j]-st.depth[i]); if (i == k) return true; } // Try using edges not in the spanning tree for (int x=0; x 0) { int hob = Integer.highestOneBit(k); int s = Integer.numberOfTrailingZeros(hob); i = par[s][i]; k ^= hob; } return i; } int lca(int i, int j) { if (depth[i] > depth[j]) i = walk(i, depth[i]-depth[j]); if (depth[i] < depth[j]) j = walk(j, depth[j]-depth[i]); if (i == j) return i; for (int d=D; d>=0; d--) { if (par[d][i] != par[d][j]) { i = par[d][i]; j = par[d][j]; } } return par[0][i]; } // Adds edge i -> j void add(int i, int j) { par[0][j] = i; depth[j] = depth[i]+1; for (int d=1; d<=D && par[d-1][j] != -1; d++) par[d][j] = par[d-1][par[d-1][j]]; } } class Graph { int N; ArrayList[] adj; Graph(int NN) { adj = new ArrayList[N=NN]; for (int i=0; i(); } void add(int i, int j) { adj[i].add(j); } Graph reverse() { Graph rev = new Graph(N); for (int i=0; i= numChars){ curChar = 0; try{ numChars = stream.read(buf); } catch (IOException e) { throw new InputMismatchException(); } if (numChars <= 0) return -1; } return buf[curChar++]; } boolean isSpaceChar(int c) { return c==' '||c=='\n'||c=='\r'||c=='\t'||c==-1; } boolean isEndline(int c) { return c=='\n'||c=='\r'||c==-1; } int nextInt() { return Integer.parseInt(next()); } long nextLong() { return Long.parseLong(next()); } double nextDouble() { return Double.parseDouble(next()); } String next(){ int c = read(); while (isSpaceChar(c)) c = read(); StringBuilder res = new StringBuilder(); do{ res.appendCodePoint(c); c = read(); }while(!isSpaceChar(c)); return res.toString(); } String nextLine(){ int c = read(); while (isEndline(c)) c = read(); StringBuilder res = new StringBuilder(); do{ res.appendCodePoint(c); c = read(); }while(!isEndline(c)); return res.toString(); } }