//O(n log(n) + m log(m) log(n)) #include <cstdio> #include <map> #include <algorithm> // #define DEBUG using namespace std; struct TrimRecord { long long day, height; TrimRecord() : day(0), height(0) {}; TrimRecord(long long day, long long height) : day(day), height(height) {}; }; const int MAXN=500005, MAXM=500005; long long n, m; long long growth[MAXN]={}; long long growthPrefSum[MAXN]={}; map<int, TrimRecord> trims; void prepareGrowthArr() { sort(&growth[1], &growth[n+1]); for (int i=1; i<=n; ++i) { growthPrefSum[i] = growthPrefSum[i-1] + growth[i]; } } void prepareTrimMap() { trims.insert(make_pair(-1, TrimRecord(0,0))); //Guard } long long getGrowthSum(int from, int to) { return growthPrefSum[to] - growthPrefSum[from-1]; } long long getHeight(int index, long long day) { map<int, TrimRecord>::iterator mit = (--trims.upper_bound(index)); return mit->second.height + (day - mit->second.day) * growth[index]; } int findIndex(TrimRecord t) { int start=1, end=n, mid; //Bin search: while (end-start>1) { mid = (start+end)/2; if (getHeight(mid, t.day) < t.height) start = mid; else end = mid; } if (getHeight(start, t.day) >= t.height) return start; if (getHeight(end, t.day) >= t.height) return end; return n+1; } void trim(TrimRecord t) { long long res = 0; int where = findIndex(t); #ifdef DEBUG fprintf(stderr, "\n\nwhere = %d\n", where); #endif int curWhere = where; map<int, TrimRecord>::iterator mit1 = trims.upper_bound(curWhere); map<int, TrimRecord>::iterator mit2 = mit1--; while (mit2 != trims.end()) { //Where were we after last cut: long long oldRect = mit1->second.height * (mit2->first - curWhere); //How much did the grass grow since then: long long additionalHeight = getGrowthSum(curWhere, mit2->first - 1) * (t.day - mit1->second.day); //Total: res += oldRect + additionalHeight; ++mit1; ++mit2; curWhere = mit1->first; } long long oldRect = mit1->second.height * ((n+1) - curWhere); long long additionalHeight = getGrowthSum(curWhere, n) * (t.day - mit1->second.day); res += oldRect + additionalHeight; //We are going to be left with some though: res -= ((n+1)-where) * t.height; //Registering new trim record: trims[where] = t; //The old trims got overwriten: trims.erase(trims.upper_bound(where), trims.end()); printf("%lld\n", res); } void debugBeforeTrim(TrimRecord curTrim) { fprintf(stderr, "\n\n\nBefore trim on day %lld to height %lld\n\n", curTrim.day, curTrim.height); fprintf(stderr, "Heights according to getHeight:\n"); for (int i=1; i<=n; ++i) { fprintf(stderr, "%lld, ", getHeight(i, curTrim.day)); } } void debugAfterTrim(TrimRecord lastTrim) { fprintf(stderr, "\n\n\nAfter trim on day %lld to height %lld\n\n", lastTrim.day, lastTrim.height); fprintf(stderr, "Heights according to getHeight:\n"); for (int i=1; i<=n; ++i) { fprintf(stderr, "%lld, ", getHeight(i, lastTrim.day)); } fprintf(stderr, "\n\nTrimMap contents:\n"); for (map<int, TrimRecord>::iterator mit=trims.begin(); mit!=trims.end(); ++ mit) { fprintf(stderr, " index=%d ; day=%lld ; height=%lld\n", mit->first, mit->second.day, mit->second.height); } fprintf(stderr, "\n##################################################################################\n"); } int main() { scanf("%lld %lld", &n, &m); for (int i=1; i<=n; ++i) //Growth indexed from 1 to n scanf("%lld", &growth[i]); prepareGrowthArr(); prepareTrimMap(); #ifdef DEBUG fprintf(stderr, "Growth:\n"); for (int i=1; i<=n; ++i) { fprintf(stderr, "%lld, ", growth[i]); } fprintf(stderr, "\n\n"); #endif TrimRecord curTrim; while(m--) { scanf("%lld %lld", &curTrim.day, &curTrim.height); #ifdef DEBUG debugBeforeTrim(curTrim); #endif trim(curTrim); #ifdef DEBUG debugAfterTrim(curTrim); #endif } return 0; }
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 170 171 172 173 174 175 176 177 178 179 180 181 | //O(n log(n) + m log(m) log(n)) #include <cstdio> #include <map> #include <algorithm> // #define DEBUG using namespace std; struct TrimRecord { long long day, height; TrimRecord() : day(0), height(0) {}; TrimRecord(long long day, long long height) : day(day), height(height) {}; }; const int MAXN=500005, MAXM=500005; long long n, m; long long growth[MAXN]={}; long long growthPrefSum[MAXN]={}; map<int, TrimRecord> trims; void prepareGrowthArr() { sort(&growth[1], &growth[n+1]); for (int i=1; i<=n; ++i) { growthPrefSum[i] = growthPrefSum[i-1] + growth[i]; } } void prepareTrimMap() { trims.insert(make_pair(-1, TrimRecord(0,0))); //Guard } long long getGrowthSum(int from, int to) { return growthPrefSum[to] - growthPrefSum[from-1]; } long long getHeight(int index, long long day) { map<int, TrimRecord>::iterator mit = (--trims.upper_bound(index)); return mit->second.height + (day - mit->second.day) * growth[index]; } int findIndex(TrimRecord t) { int start=1, end=n, mid; //Bin search: while (end-start>1) { mid = (start+end)/2; if (getHeight(mid, t.day) < t.height) start = mid; else end = mid; } if (getHeight(start, t.day) >= t.height) return start; if (getHeight(end, t.day) >= t.height) return end; return n+1; } void trim(TrimRecord t) { long long res = 0; int where = findIndex(t); #ifdef DEBUG fprintf(stderr, "\n\nwhere = %d\n", where); #endif int curWhere = where; map<int, TrimRecord>::iterator mit1 = trims.upper_bound(curWhere); map<int, TrimRecord>::iterator mit2 = mit1--; while (mit2 != trims.end()) { //Where were we after last cut: long long oldRect = mit1->second.height * (mit2->first - curWhere); //How much did the grass grow since then: long long additionalHeight = getGrowthSum(curWhere, mit2->first - 1) * (t.day - mit1->second.day); //Total: res += oldRect + additionalHeight; ++mit1; ++mit2; curWhere = mit1->first; } long long oldRect = mit1->second.height * ((n+1) - curWhere); long long additionalHeight = getGrowthSum(curWhere, n) * (t.day - mit1->second.day); res += oldRect + additionalHeight; //We are going to be left with some though: res -= ((n+1)-where) * t.height; //Registering new trim record: trims[where] = t; //The old trims got overwriten: trims.erase(trims.upper_bound(where), trims.end()); printf("%lld\n", res); } void debugBeforeTrim(TrimRecord curTrim) { fprintf(stderr, "\n\n\nBefore trim on day %lld to height %lld\n\n", curTrim.day, curTrim.height); fprintf(stderr, "Heights according to getHeight:\n"); for (int i=1; i<=n; ++i) { fprintf(stderr, "%lld, ", getHeight(i, curTrim.day)); } } void debugAfterTrim(TrimRecord lastTrim) { fprintf(stderr, "\n\n\nAfter trim on day %lld to height %lld\n\n", lastTrim.day, lastTrim.height); fprintf(stderr, "Heights according to getHeight:\n"); for (int i=1; i<=n; ++i) { fprintf(stderr, "%lld, ", getHeight(i, lastTrim.day)); } fprintf(stderr, "\n\nTrimMap contents:\n"); for (map<int, TrimRecord>::iterator mit=trims.begin(); mit!=trims.end(); ++ mit) { fprintf(stderr, " index=%d ; day=%lld ; height=%lld\n", mit->first, mit->second.day, mit->second.height); } fprintf(stderr, "\n##################################################################################\n"); } int main() { scanf("%lld %lld", &n, &m); for (int i=1; i<=n; ++i) //Growth indexed from 1 to n scanf("%lld", &growth[i]); prepareGrowthArr(); prepareTrimMap(); #ifdef DEBUG fprintf(stderr, "Growth:\n"); for (int i=1; i<=n; ++i) { fprintf(stderr, "%lld, ", growth[i]); } fprintf(stderr, "\n\n"); #endif TrimRecord curTrim; while(m--) { scanf("%lld %lld", &curTrim.day, &curTrim.height); #ifdef DEBUG debugBeforeTrim(curTrim); #endif trim(curTrim); #ifdef DEBUG debugAfterTrim(curTrim); #endif } return 0; } |