#include <bits/stdc++.h> using namespace std; template <typename T> T load() { T r; cin >> r; return r; } template <typename T> vector<T> loadMany(long long n) { vector<T> rs(n); generate(rs.begin(), rs.end(), &load<T>); return rs; } struct FU { explicit FU(long long n):link(n,-1),rank(n,0){} long long find(long long i) const { return link[i] == -1 ? i : (link[i] = find(link[i])); } bool tryUnion(long long a, long long b) { a = find(a), b = find(b); if (a == b) return false; if (rank[a] < rank[b]) swap(a, b); if (rank[a] == rank[b]) ++rank[a]; link[b] = a; return true; } private: mutable vector<long long> link; vector<long long> rank; }; struct Stove { long long duration; long long id; static long long idFactory; static bool compByDuration(Stove a, Stove b) { return a.duration < b.duration; } }; long long Stove::idFactory = 0; template <> Stove load<Stove>() { Stove stove; stove.duration = load<long long>(); stove.id = Stove::idFactory++; return stove; } class Waitblocks { struct Block { long long anchor; long long peopleCount; long long deductedWaitTime; long long rightIndex; long long undeductedWaitDurations() { return peopleCount * (peopleCount - 1) / 2; } }; struct QueueEntry { long long mergeDuration; long long leftIndex; static QueueEntry invalid() { return QueueEntry{-1,-1}; } bool isInvalid() { return mergeDuration < 0 or leftIndex < 0; } bool operator<(QueueEntry other) const { return tie(mergeDuration, leftIndex) < tie(other.mergeDuration, other.leftIndex); } }; public: explicit Waitblocks(long long n, const vector<long long>& clientTimes):n(n),fu(n),blocks(n),totalDeductedWaitTime(0),totalUndeductedWaitDurations(0){ for (long long i=0; i<n; ++i) blocks[i] = Block { clientTimes[i], 1, 0ll, i }; for (long long i=0; i<n-1; ++i) que.insert(entryBetween(i, i+1)); } long long queryNewStove(long long duration) { while (willBlocksMerge(duration)) mergeBlocks(); return totalUndeductedWaitDurations * duration - totalDeductedWaitTime; } private: QueueEntry entryBetween(long long a, long long b) { a = fu.find(a), b = fu.find(b); auto peopleBetween = blocks[a].peopleCount - 1 + 1; auto distanceBetween = blocks[b].anchor - blocks[a].anchor; auto tooBigDuration = distanceBetween / peopleBetween + 1; auto entry = QueueEntry { .mergeDuration = tooBigDuration, .leftIndex = a, }; return entry; } bool willBlocksMerge(long long duration) { return (not que.empty()) and que.begin()->mergeDuration <= duration; } void mergeBlocks() { // find the relevant entries auto entry = *que.begin(); auto ileft = getLeftBlock(entry); auto iright = getRightBlock(entry); auto inext = getNextBlock(entry); auto newBlock = Block { .anchor = blocks[ileft].anchor, .peopleCount = blocks[ileft].peopleCount + blocks[iright].peopleCount, .deductedWaitTime = blocks[ileft].deductedWaitTime + (blocks[iright].anchor - blocks[ileft].anchor) * blocks[iright].peopleCount + blocks[iright].deductedWaitTime, .rightIndex = blocks[iright].rightIndex, }; auto oldNextEntry = inext != -1 ? entryBetween(iright, inext) : QueueEntry::invalid(); auto oldDeductedWaitTime = blocks[ileft].deductedWaitTime + blocks[iright].deductedWaitTime; auto oldUndeductedWaitDurations = blocks[ileft].undeductedWaitDurations() + blocks[iright].undeductedWaitDurations(); // update the state fu.tryUnion(ileft, iright); auto inow = fu.find(ileft); blocks[inow] = newBlock; totalDeductedWaitTime -= oldDeductedWaitTime; totalDeductedWaitTime += newBlock.deductedWaitTime; totalUndeductedWaitDurations -= oldUndeductedWaitDurations; totalUndeductedWaitDurations += newBlock.undeductedWaitDurations(); que.erase(que.begin()); if (inext != -1) { auto lastEntryIter = que.find(oldNextEntry); assert(lastEntryIter != que.end()); que.erase(lastEntryIter); que.insert(entryBetween(inow, inext)); } } long long getLeftBlock(QueueEntry qe) { return fu.find(qe.leftIndex); } long long getRightBlock(QueueEntry qe) { return fu.find(blocks[getLeftBlock(qe)].rightIndex + 1); } long long getNextBlock(QueueEntry qe) { auto rawIndex = blocks[getRightBlock(qe)].rightIndex + 1; assert(rawIndex <= n); if (rawIndex == n) return -1; else return fu.find(rawIndex); } long long n; FU fu; vector<Block> blocks; long long totalDeductedWaitTime; long long totalUndeductedWaitDurations; set<QueueEntry> que; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); auto n = load<long long>()+1; auto m = load<long long>(); auto clientTimes = vector<long long>(n, 0); for (long long i=1; i<n; ++i) clientTimes[i] = load<long long>(); auto stoves = loadMany<Stove>(m); sort(stoves.begin(), stoves.end(), &Stove::compByDuration); auto waitblocks = Waitblocks(n, clientTimes); auto results = vector<long long>(m, -1); for (auto stove : stoves) results[stove.id] = waitblocks.queryNewStove(stove.duration); for (long long i=0; i<m; ++i) cout << results[i] << '\n'; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | #include <bits/stdc++.h> using namespace std; template <typename T> T load() { T r; cin >> r; return r; } template <typename T> vector<T> loadMany(long long n) { vector<T> rs(n); generate(rs.begin(), rs.end(), &load<T>); return rs; } struct FU { explicit FU(long long n):link(n,-1),rank(n,0){} long long find(long long i) const { return link[i] == -1 ? i : (link[i] = find(link[i])); } bool tryUnion(long long a, long long b) { a = find(a), b = find(b); if (a == b) return false; if (rank[a] < rank[b]) swap(a, b); if (rank[a] == rank[b]) ++rank[a]; link[b] = a; return true; } private: mutable vector<long long> link; vector<long long> rank; }; struct Stove { long long duration; long long id; static long long idFactory; static bool compByDuration(Stove a, Stove b) { return a.duration < b.duration; } }; long long Stove::idFactory = 0; template <> Stove load<Stove>() { Stove stove; stove.duration = load<long long>(); stove.id = Stove::idFactory++; return stove; } class Waitblocks { struct Block { long long anchor; long long peopleCount; long long deductedWaitTime; long long rightIndex; long long undeductedWaitDurations() { return peopleCount * (peopleCount - 1) / 2; } }; struct QueueEntry { long long mergeDuration; long long leftIndex; static QueueEntry invalid() { return QueueEntry{-1,-1}; } bool isInvalid() { return mergeDuration < 0 or leftIndex < 0; } bool operator<(QueueEntry other) const { return tie(mergeDuration, leftIndex) < tie(other.mergeDuration, other.leftIndex); } }; public: explicit Waitblocks(long long n, const vector<long long>& clientTimes):n(n),fu(n),blocks(n),totalDeductedWaitTime(0),totalUndeductedWaitDurations(0){ for (long long i=0; i<n; ++i) blocks[i] = Block { clientTimes[i], 1, 0ll, i }; for (long long i=0; i<n-1; ++i) que.insert(entryBetween(i, i+1)); } long long queryNewStove(long long duration) { while (willBlocksMerge(duration)) mergeBlocks(); return totalUndeductedWaitDurations * duration - totalDeductedWaitTime; } private: QueueEntry entryBetween(long long a, long long b) { a = fu.find(a), b = fu.find(b); auto peopleBetween = blocks[a].peopleCount - 1 + 1; auto distanceBetween = blocks[b].anchor - blocks[a].anchor; auto tooBigDuration = distanceBetween / peopleBetween + 1; auto entry = QueueEntry { .mergeDuration = tooBigDuration, .leftIndex = a, }; return entry; } bool willBlocksMerge(long long duration) { return (not que.empty()) and que.begin()->mergeDuration <= duration; } void mergeBlocks() { // find the relevant entries auto entry = *que.begin(); auto ileft = getLeftBlock(entry); auto iright = getRightBlock(entry); auto inext = getNextBlock(entry); auto newBlock = Block { .anchor = blocks[ileft].anchor, .peopleCount = blocks[ileft].peopleCount + blocks[iright].peopleCount, .deductedWaitTime = blocks[ileft].deductedWaitTime + (blocks[iright].anchor - blocks[ileft].anchor) * blocks[iright].peopleCount + blocks[iright].deductedWaitTime, .rightIndex = blocks[iright].rightIndex, }; auto oldNextEntry = inext != -1 ? entryBetween(iright, inext) : QueueEntry::invalid(); auto oldDeductedWaitTime = blocks[ileft].deductedWaitTime + blocks[iright].deductedWaitTime; auto oldUndeductedWaitDurations = blocks[ileft].undeductedWaitDurations() + blocks[iright].undeductedWaitDurations(); // update the state fu.tryUnion(ileft, iright); auto inow = fu.find(ileft); blocks[inow] = newBlock; totalDeductedWaitTime -= oldDeductedWaitTime; totalDeductedWaitTime += newBlock.deductedWaitTime; totalUndeductedWaitDurations -= oldUndeductedWaitDurations; totalUndeductedWaitDurations += newBlock.undeductedWaitDurations(); que.erase(que.begin()); if (inext != -1) { auto lastEntryIter = que.find(oldNextEntry); assert(lastEntryIter != que.end()); que.erase(lastEntryIter); que.insert(entryBetween(inow, inext)); } } long long getLeftBlock(QueueEntry qe) { return fu.find(qe.leftIndex); } long long getRightBlock(QueueEntry qe) { return fu.find(blocks[getLeftBlock(qe)].rightIndex + 1); } long long getNextBlock(QueueEntry qe) { auto rawIndex = blocks[getRightBlock(qe)].rightIndex + 1; assert(rawIndex <= n); if (rawIndex == n) return -1; else return fu.find(rawIndex); } long long n; FU fu; vector<Block> blocks; long long totalDeductedWaitTime; long long totalUndeductedWaitDurations; set<QueueEntry> que; }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); auto n = load<long long>()+1; auto m = load<long long>(); auto clientTimes = vector<long long>(n, 0); for (long long i=1; i<n; ++i) clientTimes[i] = load<long long>(); auto stoves = loadMany<Stove>(m); sort(stoves.begin(), stoves.end(), &Stove::compByDuration); auto waitblocks = Waitblocks(n, clientTimes); auto results = vector<long long>(m, -1); for (auto stove : stoves) results[stove.id] = waitblocks.queryNewStove(stove.duration); for (long long i=0; i<m; ++i) cout << results[i] << '\n'; } |