C - Division
思路:我们考虑到一点,从大往小取得顺序是不会有问题的,所以可以直接主席树,但是开不下空间,我们可以log分段求。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; int n, q, all, hs[2 * N], hcnt, a[N], bin[31]; LL ans[5 * N], sum[N], csum[N]; pair<PII, int> qus[5 * N]; vector<int> vc[30][N]; int root[2 * N], tot; struct node { LL sum; int cnt, ls, rs; } o[2 * N * 20]; void update(int p, int l, int r, int &x, int y) { x = ++tot; o[x] = o[y]; o[x].sum += p; o[x].cnt++; if(l == r) return; int mid = l + r >> 1; if(p <= hs[mid]) update(p, l, mid, o[x].ls, o[y].ls); else update(p, mid + 1, r, o[x].rs, o[y].rs); } LL query(int res, int l, int r, int x, int y) { if(o[x].cnt - o[y].cnt <= res) return o[x].sum - o[y].sum; if(l == r) return 1ll * res * hs[l]; int mid = l + r >> 1, cntr = o[o[x].rs].cnt - o[o[y].rs].cnt; if(cntr >= res) return query(res, mid + 1, r, o[x].rs, o[y].rs); else return o[o[x].rs].sum - o[o[y].rs].sum + query(res-cntr, l, mid, o[x].ls, o[y].ls); } int main() { for(int i = bin[0] = 1; i <= 30; i++) bin[i] = bin[i - 1] << 1; scanf("%d%d", &n, &q); for(int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i]; for(int i = 1; i <= q; i++) { scanf("%d%d%d", &qus[i].fi.fi, &qus[i].fi.se, &qus[i].se); ans[i] = sum[qus[i].fi.se] - sum[qus[i].fi.fi - 1]; } for(int i = 1, j = 29; i <= n; i++, j = 29) { while(a[i]) { int val = a[i] - a[i] / 2; while(val < bin[j]) j--; vc[j][i].push_back(val); a[i] /= 2; } } for(int k = 29; k >= 0; k--) { tot = 0; hcnt = 0; all = 0; for(int i = 1; i <= n; i++) csum[i] = csum[i - 1] + SZ(vc[k][i]); if(!csum[n]) continue; for(int i = 1; i <= n; i++) for(auto& t : vc[k][i]) hs[++hcnt] = t; sort(hs + 1, hs + 1 + hcnt); hcnt = unique(hs + 1, hs + 1 + hcnt) - hs - 1; for(int i = 1; i <= n; i++) for(auto& t : vc[k][i]) update(t, 1, hcnt, root[all + 1], root[all]), all++; for(int i = 1; i <= q; i++) { if(!qus[i].se) continue; int L = qus[i].fi.fi, R = qus[i].fi.se, has = csum[R] - csum[L - 1]; if(has >= qus[i].se) { ans[i] -= query(qus[i].se, 1, hcnt, root[csum[R]], root[csum[L - 1]]); qus[i].se = 0; } else { ans[i] -= query(has, 1, hcnt, root[csum[R]], root[csum[L - 1]]); qus[i].se -= has; } } } for(int i = 1; i <= q; i++) printf("%lld ", ans[i]); return 0; } /* */