抄的ygg代码,向在这里说一下刚开始没看懂的部分。
求答案的时候是把所有的当前为止的所有数值加起来减去一个从1开始并且公差为1的等差数列的前size项和。其中size是当前最多能用到哪个位置,满足前size项能构成1,2,3,....,sz这样的形式。
假设我们的a[] = {1, 4, 4, 4, 3},在i等于4的时候答案是3,在i等于5的时候答案是2,由于我们给线段树上每个为i的位置插入了-i,当i = 4的时候线段树叶子结点[0, -1, -2, 0, -1],当i == 5时候线段树的叶子结点为[0, -1, -1, 1, 0]。这个时候我们就可以找出到i为止多余的数字,并且减去他所造成的影响。
#include <bits/stdc++.h>
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
#define ls u << 1
#define rs u << 1 | 1
int n, m;
int a[N];
struct node {
int lazy;
int v;
}tr[N << 2];
inline void pushup(int u) {
tr[u].v = std::max(tr[ls].v, tr[rs].v);
}
inline void pushdown(int u) {
if (tr[u].lazy) {
int &v = tr[u].lazy;
tr[ls].lazy += v;
tr[ls].v += v;
tr[rs].lazy += v;
tr[rs].v += v;
v = 0;
}
}
inline void build(int u, int L, int R) {
tr[u].lazy = tr[u].v = 0;
if (L == R) return ;
int mid = L + R >> 1;
build(ls, L, mid);
build(rs, mid + 1, R);
pushup(u);
}
inline void modify(int u, int L, int R, int l, int r, int v) {
if (L >= l && R <= r) {
tr[u].lazy += v;
tr[u].v += v;
return ;
}
pushdown(u);
int mid = L + R >> 1;
if (l <= mid) modify(ls, L, mid, l, r, v);
if (r > mid) modify(rs, mid + 1, R, l, r, v);
pushup(u);
}
inline int query(int u, int L, int R) {
if (L == R) return L;
pushdown(u);
int mid = L + R >> 1;
if (tr[ls].v > 0) return query(ls, L, mid);
return query(rs, mid + 1, R);
}
inline void solve() {
std::cin >> n;
for (int i = 1; i <= n; i ++) std::cin >> a[i];
build(1, 1, n);
for (int i = 1; i <= n; i ++) {
modify(1, 1, n, i, i, -i);
}
ll sum = 0, sz = 0;
for (int i = 1; i <= n; i ++) {
sum += a[i], sz ++;
modify(1, 1, n, a[i], n, 1);
if (tr[1].v > 0) {
int now = query(1, 1, n);
sz --, sum -= now;
modify(1, 1, n, now, n, -1);
}
std::cout << sum - sz * (sz + 1) / 2 << ' ';
}
std::cout << '\n';
}
int main(void) {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _;
_ = 1;
std::cin >> _;
while (_ --) solve();
return 0;
}
标签:based,int,线段,hard,mid,return,ls,query,Round
From: https://www.cnblogs.com/qdhys/p/17334523.html