/* * rainbowRoads_sjz.cpp * * Created on: Oct 4, 2017 * Author: zeil */ #include #include #include #include #include #include using namespace std; typedef int BadgeNum; typedef int EdgeNum; typedef int VertexNum; BadgeNum nB; VertexNum nV; EdgeNum nE; typedef map BadgeSet; typedef BadgeSet::value_type Interval; bool insertRange (BadgeSet& bset, int low, int high) { bool changed = true; auto stop = bset.upper_bound(high); if (stop != bset.begin()) { // See if the preceding range merges with this one --stop; if (stop->second >= high) { high = stop->second; } ++stop; auto start = bset.lower_bound(low); if (start != bset.begin()) { --start; if (start->second >= low) { low = start->first; } else { ++start; } } changed = start == stop || (start != bset.end() && (start->first > low || start->second < high)); if (changed) { bset.erase(start, stop); } } if (changed) bset.insert(Interval(low,high)); return changed; } struct Edge { VertexNum source; VertexNum dest; BadgeNum min; BadgeNum max; bool inQ; Edge (VertexNum asource, VertexNum adest, BadgeNum amin, BadgeNum amax) : source(asource), dest(adest), min(amin), max(amax), inQ(false) {} }; struct Vertex { list outEdges; BadgeSet reached; }; Vertex* vertex; ostream& operator<< (ostream& out, const Interval& i) { out << i.first << ".." << i.second; return out; } ostream& operator<< (ostream& out, const BadgeSet& b) { out << '{'; bool first = true; for (const Interval& i: b) { if (!first) out << ", "; out << i; first = false; } out << "}"; return out; } ostream& operator<< (ostream& out, const Edge& e) { out << e.source << "=>" << e.dest << " [" << e.min << ".." << e.max << "]"; return out; } bool overlaps (Interval int1, Interval int2) { return !(int1.first > int2.second || int1.second < int2.first); } void propogateBadgeNumbers(VertexNum start) { vertex[start].reached.insert(Interval(0, nB-1)); list queue; for (Edge e: vertex[start].outEdges) { queue.push_back(e); e.inQ = true; } int qcnt = 0; while (!queue.empty()) { ++qcnt; Edge e = queue.front(); queue.pop_front(); e.inQ = false; // cerr << "edge: " << e << endl; BadgeSet& prop = vertex[e.source].reached; std::map,allocator>>::iterator sourceStart = prop.lower_bound(e.min); Interval edgeFilter (e.min, e.max); if (sourceStart != prop.begin()) { --sourceStart; if (sourceStart->second < e.min) { ++sourceStart; } } bool changed = false; for (auto it = sourceStart; it != prop.end(); ++it) { const Interval& sourceContent = *it; if (sourceContent.first > e.max) break; if (overlaps(sourceContent, edgeFilter)) { Interval newPart (max(sourceContent.first, e.min), min(sourceContent.second, e.max)); if (newPart.first <= newPart.second) { BadgeSet& destBadges = vertex[e.dest].reached; changed |= insertRange (destBadges, newPart.first, newPart.second); } } } cerr << e.dest << " becomes " << vertex[e.dest].reached << endl; if (changed) { cerr << e.dest << " has changed." << endl; for (Edge e2: vertex[e.dest].outEdges) { if (!e2.inQ) { queue.push_back(e2); e2.inQ = true; } } } } cerr << "Queue visited " << qcnt << " times" << endl; } void printReached(VertexNum v) { int count = 0; for (const auto& interval: vertex[v].reached) { // cerr << interval << endl; count += interval.second - interval.first + 1; } cout << count << endl; } void solve (istream& in) { in >> nV >> nE >> nB; VertexNum start, stop; in >> start >> stop; start--; stop-- ; vertex = new Vertex[nV]; for (int i = 0; i < nE; ++i) { int d, s, mn, mx; in >> s >> d >> mn >> mx; s-- ; d-- ; mn-- ; mx-- ; vertex[s].outEdges.push_back(Edge(s, d, mn, mx)); } propogateBadgeNumbers(start); printReached(stop); } int main (int argc, char** argv) { if (argc > 1) { ifstream in (argv[1]); solve(in); } else { solve (cin); } }