题解:P9388 [THUPC 2023 决赛] 先人类的人类选别
Danslapiscine · · 题解
需要观察。
可以注意到做一次操作,相当于将一个数加入,然后将一个最小的数移除。这便于统计操作后的和。进一步观察到修改操作的相似性:他们都从
那么对于一个数列大小为
根据性质,容易想到将所有操作的数打包起来维护;将
#include <bits/stdc++.h>
using namespace std;
int n, m, a;
struct Chairman_Tree{
int tot, root[500002];
struct Node {
int lson, rson;
long long sum;
int siz;
}t[10000002];
void Add(int lroot,int pos,int l,int r,int tar){
t[pos] = t[lroot];
if(l == r){
t[pos].siz++;
t[pos].sum += l;
return;
}
int mid = (l + r) >> 1;
if(tar <= mid){
t[pos].lson = ++tot;
Add(t[lroot].lson, t[pos].lson, l, mid, tar);
}
else {
t[pos].rson = ++tot;
Add(t[lroot].rson, t[pos].rson, mid+1, r, tar);
}
t[pos].siz = t[t[pos].lson].siz + t[t[pos].rson].siz;
t[pos].sum = t[t[pos].lson].sum + t[t[pos].rson].sum;
}
};
Chairman_Tree C;
#define l(pos) pos << 1
#define r(pos) (pos << 1) | 1
struct Segment_Tree{
long long sum[2000002];
int siz[2000002];
void Add(int pos,int l,int r,int tar){
if(l == r){
siz[pos]++;
sum[pos] += l;
return;
}
int mid = (l + r) >> 1;
if(tar <= mid){
Add(l(pos), l, mid, tar);
}
else {
Add(r(pos), mid+1, r, tar);
}
siz[pos] = siz[l(pos)] + siz[r(pos)];
sum[pos] = sum[l(pos)] + sum[r(pos)];
}
};
Segment_Tree T;
long long Solve(int pos1,int pos2,int l,int r,int k){
if(l == r){
return 1ll * k * l;
}
int mid = (l + r) >> 1, S = T.siz[r(pos1)] + C.t[C.t[pos2].rson].siz;
if(k <= S) return Solve(r(pos1), C.t[pos2].rson, mid+1, r, k);
else return T.sum[r(pos1)] + C.t[C.t[pos2].rson].sum + Solve(l(pos1), C.t[pos2].lson, l, mid, k - S);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a);
C.tot++, C.root[i] = C.tot;
C.Add(C.root[i-1], C.root[i], 1, n, a);
}
while(m--){
int l, r, x;
scanf("%d%d%d",&x,&l,&r);
T.Add(1, 1, n, x);
printf("%lld\n",Solve(1, C.root[r], 1, n, r) - Solve(1, C.root[l-1], 1, n, l-1));
}
return 0;
}