matistjati

Untitled

Jul 11th, 2026
10
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.02 KB | None | 0 0
  1. #pragma GCC optimize("O3")
  2. #include <bits/allocator.h>
  3. #pragma GCC target("avx2")
  4. #include <bits/stdc++.h>
  5. using namespace std;
  6.  
  7. using ll = long long;
  8. using vi = vector<ll>;
  9. using vvi = vector<vi>;
  10. using p2 = pair<ll, ll>;
  11. const ll inf = 1e18;
  12.  
  13. #define repe(i, arr) for (auto& i : arr)
  14. #define rep(i, b) for(ll i = 0; i < (b); ++i)
  15. #define repp(i, a, b) for(ll i = a; i < (b); ++i)
  16. #define all(x) begin(x),end(x)
  17. #define sz(x) ((ll)x.size())
  18.  
  19. namespace lines {
  20. using big_signed = __int128;
  21.  
  22. struct Line {
  23. short k; // slopes bounded by blocksize, int suffices
  24. ll m; // y = kx + m
  25. bool operator<(const Line& o) const {
  26. return k < o.k;
  27. }
  28. Line operator+(const Line& other) const {
  29. return { (short)(k + other.k), m + other.m };
  30. }
  31. ll eval(ll x) const {
  32. return k * x + m;
  33. }
  34. };
  35.  
  36. bool better(const Line& a, const Line& b, ll x) {
  37. return a.eval(x) >= b.eval(x);
  38. }
  39.  
  40. ll eval(const vector<Line>& sp, ll x) {
  41. int l = 0, r = sp.size() - 1;
  42. while (l < r) {
  43. int m = (l + r) / 2;
  44. if (better(sp[m], sp[m + 1], x)) r = m;
  45. else l = m + 1;
  46. }
  47. return sp[l].eval(x);
  48. }
  49.  
  50. inline bool intersection_geq(const Line& A, const Line& B, const Line& C) {
  51. auto left = (big_signed)(B.m - A.m) * (A.k - C.k);
  52. auto right = (big_signed)(C.m - A.m) * (A.k - B.k);
  53. return left >= right;
  54. }
  55.  
  56. void hullify_vector(vector<Line>& lines)
  57. {
  58. int hsz = 0;
  59. for (auto& l : lines) {
  60. while (hsz >= 2 && intersection_geq(lines[hsz - 2], lines[hsz - 1], l)) {
  61. --hsz;
  62. }
  63. lines[hsz++] = l;
  64. }
  65.  
  66. lines.resize(hsz);
  67. }
  68.  
  69. bool intersect_less(const Line& a1, const Line& a2, const Line& b1, const Line& b2) {
  70. big_signed numA = (big_signed)a2.m - (big_signed)a1.m;
  71. big_signed denA = (big_signed)a1.k - (big_signed)a2.k;
  72. big_signed numB = (big_signed)b2.m - (big_signed)b1.m;
  73. big_signed denB = (big_signed)b1.k - (big_signed)b2.k;
  74. return numA * denB < numB * denA;
  75. }
  76.  
  77. void minkowski_sum_dense(vector<ll>& res, const vector<Line>& A, const vector<Line>& B) {
  78. int i = 0, j = 0, n = (int)A.size(), m = (int)B.size();
  79. while (i < n && j < m) {
  80. Line l = A[i] + B[j];
  81. res[l.k] = max(res[l.k], l.m);
  82. if (i + 1 == n) ++j;
  83. else if (j + 1 == m) ++i;
  84. else (intersect_less(A[i], A[i + 1], B[j], B[j + 1]) ? i : j)++;
  85. }
  86. while (i < n) { Line l = A[i++] + B.back(); res[l.k] = max(res[l.k], l.m); }
  87. while (j < m) { Line l = A.back() + B[j++]; res[l.k] = max(res[l.k], l.m); }
  88. }
  89.  
  90. struct Tree
  91. {
  92. int blocksize;
  93. vector<ll> lazy;
  94. span<ll> block;
  95. vector<vector<Line>> pref;
  96. vector<vector<Line>> suf;
  97. vector<vector<ll>> all_m; // dense: all lines. all_m[x][k] = max m for kx+m in node x
  98. vector<Line> all_lines_root;
  99. bool root_dirty = true;
  100. vector<ll> tot;
  101. Tree() {}
  102. Tree(int blocksize, vi& blockv) : blocksize(blocksize), lazy(blocksize * 2), block(span<ll>(all(blockv))),
  103. pref(blocksize * 2), suf(blocksize * 2), all_m(blocksize * 2),
  104. tot(blocksize * 2)
  105. {
  106. build(1, 0, blocksize - 1);
  107. }
  108.  
  109. void rebuild_node(int x, int l, int r)
  110. {
  111. int width = r - l + 1;
  112. int lsz, rsz;
  113.  
  114. // Build pref
  115. lsz = pref[x * 2].size();
  116. rsz = pref[x * 2 + 1].size();
  117. pref[x].resize(lsz + rsz);
  118. memcpy(pref[x].data(), pref[x * 2].data(), lsz * sizeof(Line));
  119. memcpy(pref[x].data() + lsz, pref[x * 2 + 1].data(), rsz * sizeof(Line));
  120. for (int i = lsz; i < lsz + rsz; i++) {
  121. pref[x][i].k += width / 2;
  122. pref[x][i].m += tot[x * 2];
  123. }
  124. hullify_vector(pref[x]);
  125.  
  126. lsz = suf[x * 2 + 1].size();
  127. rsz = suf[x * 2].size();
  128. suf[x].resize(lsz + rsz);
  129. memcpy(suf[x].data(), suf[x * 2 + 1].data(), lsz * sizeof(Line));
  130. memcpy(suf[x].data() + lsz, suf[x * 2].data(), rsz * sizeof(Line));
  131. for (int i = lsz; i < lsz + rsz; i++) {
  132. suf[x][i].k += width / 2;
  133. suf[x][i].m += tot[x * 2 + 1];
  134. }
  135. hullify_vector(suf[x]);
  136.  
  137. all_m[x].assign(width + 1, -inf);
  138. all_m[x][0] = 0;
  139.  
  140. minkowski_sum_dense(all_m[x], suf[x * 2], pref[x * 2 + 1]);
  141.  
  142. ll* __restrict dst = all_m[x].data();
  143. const ll* __restrict lsrc = all_m[x * 2].data();
  144. const ll* __restrict rsrc = all_m[x * 2 + 1].data();
  145.  
  146. int left_width = width / 2;
  147. rep(k, left_width + 1) {
  148. dst[k] = max({dst[k], lsrc[k], rsrc[k]});
  149. }
  150.  
  151. tot[x] = tot[x * 2] + tot[x * 2 + 1];
  152. if (x == 1) root_dirty = true;
  153. }
  154.  
  155. void build(int x, int l, int r)
  156. {
  157. if (l == r) {
  158. tot[x] = block[l];
  159. pref[x] = { {1,block[l]} };
  160. suf[x] = { {1,block[l]} };
  161. all_m[x] = { 0, block[l] };
  162. return;
  163. }
  164.  
  165. int mid = (l + r) / 2;
  166. build(x * 2, l, mid);
  167. build(x * 2 + 1, mid + 1, r);
  168.  
  169. int width = r - l + 1;
  170. pref[x].reserve(width);
  171. suf[x].reserve(width);
  172. rebuild_node(x, l, r);
  173. }
  174.  
  175. void hullify_root() {
  176. if (!root_dirty) return;
  177. all_lines_root.clear();
  178. for (int k = 0; k < (int)all_m[1].size(); k++) {
  179. if (all_m[1][k] > -inf) {
  180. all_lines_root.push_back({(short)k, all_m[1][k]});
  181. }
  182. }
  183. hullify_vector(all_lines_root);
  184. root_dirty = false;
  185. }
  186.  
  187. vector<Line>& get_all_lines() {
  188. hullify_root();
  189. return all_lines_root;
  190. }
  191.  
  192. void reset()
  193. {
  194. rep(i, sz(lazy)) lazy[i] = 0;
  195. build(1, 0, blocksize - 1);
  196. root_dirty = true;
  197. }
  198.  
  199. inline void put_tag(int x, int width, ll w)
  200. {
  201. if (!w) return;
  202. tot[x] += w * width;
  203. ll* __restrict am = all_m[x].data();
  204. rep(k, width + 1) am[k] += (ll)k * w;
  205. repe(l, pref[x]) l.m += l.k * w;
  206. repe(l, suf[x]) l.m += l.k * w;
  207. lazy[x] += w;
  208. if (x == 1) root_dirty = true;
  209. }
  210.  
  211. void add(int x, int l, int r, int ql, int qr, ll w, ll inherited=0)
  212. {
  213. int width = r - l + 1;
  214. if (r < ql || l > qr)
  215. {
  216. put_tag(x, width, inherited);
  217. return;
  218. }
  219. if (l >= ql && r <= qr)
  220. {
  221. put_tag(x, width, inherited + w);
  222. return;
  223. }
  224.  
  225. int mid = (l + r) / 2;
  226. add(x * 2, l, mid, ql, qr, w, inherited + lazy[x]);
  227. add(x * 2 + 1, mid + 1, r, ql, qr, w, inherited + lazy[x]);
  228. lazy[x] = 0;
  229.  
  230. // forced to rebuild
  231. rebuild_node(x, l, r);
  232. }
  233. };
  234. };
  235.  
  236. using lines::Line;
  237.  
  238. struct Blockres
  239. {
  240. ll sum = 0, prefmax = 0, sufmax = 0, ans = 0;
  241. Blockres() {}
  242. Blockres(ll val) : sum(val), prefmax(max(0LL, val)), sufmax(max(0LL, val)), ans(max(0LL, val)) {}
  243. Blockres(ll sum, ll prefmax, ll sufmax, ll ans) : sum(sum), prefmax(prefmax), sufmax(sufmax), ans(ans) {}
  244. Blockres merge(Blockres o)
  245. {
  246. Blockres ret = *this;
  247. ret.ans = max({ ret.ans, o.ans, ret.sufmax + o.prefmax });
  248. ret.prefmax = max(ret.prefmax, ret.sum + o.prefmax);
  249. ret.sufmax = max(o.sufmax, o.sum + ret.sufmax);
  250. ret.sum += o.sum;
  251. return ret;
  252. }
  253. };
  254.  
  255. vector<Blockres> answers;
  256. vi arr;
  257. struct Blockdata
  258. {
  259. int bl, br;
  260. ll lazy_add = 0;
  261. ll tot = 0;
  262. int blocksize;
  263. vi block;
  264. Blockdata(int blocksize) : blocksize(blocksize), block(blocksize) {}
  265.  
  266. void reset(int bl, int br)
  267. {
  268. this->bl = bl;
  269. this->br = br;
  270. lazy_add = 0;
  271.  
  272. rep(i, blocksize) block[i] = arr[i + bl];
  273. tot = accumulate(all(block), 0LL);
  274.  
  275. update_hull(0, blocksize - 1, 0, true);
  276. }
  277.  
  278. lines::Tree ans_hull;
  279.  
  280. void update_hull(int l, int r, ll w, bool rebuild = false)
  281. {
  282. if (!sz(ans_hull.lazy) || rebuild)
  283. {
  284. if (!sz(ans_hull.lazy)) ans_hull = lines::Tree(blocksize, block);
  285. else ans_hull.reset();
  286. }
  287. else
  288. {
  289. ans_hull.add(1, 0, blocksize - 1, l - bl, r - bl, w);
  290. }
  291. }
  292.  
  293. void handle_partial_update(int l, int r, ll w)
  294. {
  295. // update block and tot incrementally
  296. tot += lazy_add * blocksize;
  297. rep(i, blocksize) block[i] += lazy_add;
  298.  
  299. int cnt = min(r + 1, br) - max(l, bl);
  300. tot += w * cnt;
  301. repp(i, max(l, bl), min(r + 1, br)) block[i - bl] += w;
  302.  
  303. ans_hull.add(1, 0, blocksize - 1, 0, blocksize - 1, lazy_add);
  304.  
  305. lazy_add = 0;
  306. update_hull(l, r, w);
  307. }
  308.  
  309. vector<pair<ll,int>> waiting_full;
  310.  
  311. inline ll div(ll a, ll b) {
  312. return a / b - ((a ^ b) < 0 && a % b);
  313. }
  314.  
  315. void solve_big()
  316. {
  317. static vector<ll> xright_all, xright_pref, xright_suf;
  318.  
  319. auto compute_xright = [&](const vector<Line>& lines, vector<ll>& out) {
  320. out.clear();
  321. for (int i = 0; i + 1 < (int)lines.size(); i++) {
  322. const Line& a = lines[i];
  323. const Line& b = lines[i + 1];
  324. if (a.k != b.k) {
  325. ll x = div(b.m - a.m, a.k - b.k);
  326. out.push_back(x);
  327. }
  328. }
  329. };
  330.  
  331. auto& all_hull = ans_hull.get_all_lines();
  332. auto& pref_hull = ans_hull.pref[1];
  333. auto& suf_hull = ans_hull.suf[1];
  334.  
  335. compute_xright(all_hull, xright_all);
  336. compute_xright(pref_hull, xright_pref);
  337. compute_xright(suf_hull, xright_suf);
  338.  
  339. for (auto [lazy, q_ind] : waiting_full)
  340. {
  341. int idx = upper_bound(all(xright_all), lazy) - xright_all.begin();
  342. ll bestinside = all_hull[idx].eval(lazy);
  343.  
  344. idx = upper_bound(all(xright_pref), lazy) - xright_pref.begin();
  345. ll bestpref = pref_hull[idx].eval(lazy);
  346.  
  347. idx = upper_bound(all(xright_suf), lazy) - xright_suf.begin();
  348. ll bestsuf = suf_hull[idx].eval(lazy);
  349.  
  350. Blockres blockres(tot + lazy * blocksize, bestpref, bestsuf, bestinside);
  351. answers[q_ind] = answers[q_ind].merge(blockres);
  352. }
  353.  
  354. waiting_full.clear();
  355. }
  356.  
  357. void pop_queries()
  358. {
  359. if (sz(waiting_full) == 0) return;
  360. if (sz(waiting_full) > 1000)
  361. {
  362. solve_big();
  363. return;
  364. }
  365.  
  366. auto& all_hull = ans_hull.get_all_lines();
  367. auto& pref_hull = ans_hull.pref[1];
  368. auto& suf_hull = ans_hull.suf[1];
  369.  
  370. for (auto [lazy, q_ind] : waiting_full)
  371. {
  372. ll bestinside = lines::eval(all_hull, lazy);
  373. ll bestpref = lines::eval(pref_hull, lazy);
  374. ll bestsuf = lines::eval(suf_hull, lazy);
  375.  
  376. Blockres block(tot + lazy * blocksize, bestpref, bestsuf, bestinside);
  377. answers[q_ind] = answers[q_ind].merge(block);
  378. }
  379. waiting_full.clear();
  380. }
  381. };
  382.  
  383.  
  384. struct Query
  385. {
  386. bool update : 1;
  387. unsigned int l : 19;
  388. unsigned int r : 19;
  389. int w : 25;
  390. };
  391.  
  392. vector<Blockres> solve(vi arrin, vector<Query> queries, int blocksize)
  393. {
  394. int n = sz(arrin);
  395. arr = arrin;
  396. int numq = 0;
  397. for (auto [upd, l, r, w] : queries)
  398. {
  399. if (!upd) numq++;
  400. }
  401. answers.resize(numq);
  402. int numblocks = n / blocksize;
  403.  
  404. Blockdata currblock(blocksize);
  405. rep(b, numblocks)
  406. {
  407. unsigned int bl = b * blocksize;
  408. unsigned int br = (b + 1) * blocksize;
  409. currblock.reset(bl, br);
  410.  
  411. auto fully_outside = [&](int l, int r)
  412. {
  413. if (r < bl || l >= br) return true;
  414. return false;
  415. };
  416. auto fully_inside = [&](int l, int r)
  417. {
  418. if (bl >= l && br - 1 <= r) return true;
  419. return false;
  420. };
  421.  
  422. auto update_hull = [&](int l, int r, ll w)
  423. {
  424. currblock.handle_partial_update(l, r, w);
  425. };
  426. update_hull(0, 0, 0);
  427.  
  428. int qind = -1;
  429.  
  430. for (auto [upd, l, r, w] : queries)
  431. {
  432. if (!upd) qind++;
  433. if (fully_outside(l, r)) continue;
  434. if (fully_inside(l, r))
  435. {
  436. if (upd)
  437. {
  438. currblock.lazy_add += w;
  439. }
  440. else
  441. {
  442. currblock.waiting_full.emplace_back(currblock.lazy_add, qind);
  443. }
  444. }
  445. else // partially inside
  446. {
  447. if (upd)
  448. {
  449. // pop all waiting queries
  450. currblock.pop_queries();
  451.  
  452. update_hull(l, r, w);
  453. }
  454. else // partially inside query: handle naive
  455. {
  456. repp(i, max(l, bl), min(r + 1u, br))
  457. {
  458. ll val = currblock.block[i - bl] + currblock.lazy_add;
  459. answers[qind] = answers[qind].merge(Blockres(val));
  460. }
  461. }
  462. }
  463. }
  464. currblock.pop_queries();
  465. }
  466.  
  467. return answers;
  468. }
  469.  
  470. int main()
  471. {
  472. cin.tie(0)->sync_with_stdio(0);
  473.  
  474. int n, q;
  475. cin >> n >> q;
  476. vi arr(n);
  477. rep(i, n) cin >> arr[i];
  478.  
  479. int numq = 0;
  480. vector<Query> queries;
  481. queries.reserve(q);
  482. rep(i, q)
  483. {
  484. char c;
  485. cin >> c;
  486. if (c == '+')
  487. {
  488. unsigned int l, r;
  489. int w;
  490. cin >> l >> r >> w;
  491. l--; r--;
  492. Query qu = { 1,l,r,w };
  493. queries.push_back(qu);
  494. }
  495. else
  496. {
  497. unsigned int l, r;
  498. cin >> l >> r;
  499. l--; r--;
  500. numq++;
  501. Query qu = { 0, l,r,0 };
  502. queries.push_back(qu);
  503. }
  504. }
  505.  
  506. int blocksize = 512; // For some reason, a const blocksize is slower
  507.  
  508. while (sz(arr) % (blocksize) != 0)
  509. {
  510. n++;
  511. arr.push_back(0);
  512. }
  513.  
  514. vector<Blockres> ans = solve(arr, queries, blocksize);
  515.  
  516. rep(i, sz(ans))
  517. {
  518. cout << ans[i].ans << '\n';
  519. }
  520.  
  521. return 0;
  522. }
  523.  
Advertisement
Add Comment
Please, Sign In to add comment