题解:P9388 [THUPC 2023 决赛] 先人类的人类选别
一个重要的观察:第
证明显然,对于前
于是有转化:第
现在我们考虑怎么求原序列的一段前缀 和 操作序列的前
时间复杂度
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500005;
int n,m,a[N],f[N<<5],rt[N],ls[N<<5],rs[N<<5],sz[N<<5],cnt,RT,sum[N];
int update(int nroot,int l,int r,int x)
{
int root = ++cnt;
f[root] = f[nroot],sz[root] = sz[nroot];
f[root] += x;
sz[root]++;
if (l >= r) return root;
int mid = (l+r)/2;
if (x <= mid) ls[root] = update(ls[nroot],l,mid,x),rs[root] = rs[nroot];
else rs[root] = update(rs[nroot],mid+1,r,x),ls[root] = ls[nroot];
return root;
}
int updateq(int root,int l,int r,int x)
{
if (!root) root = ++cnt;
f[root] += x;
sz[root]++;
if (l >= r)
{
return root;
}
int mid = (l+r)/2;
if (x <= mid) ls[root] = updateq(ls[root],l,mid,x);
else rs[root] = updateq(rs[root],mid+1,r,x);
return root;
}
int query(int root1,int root2,int l,int r,int k)
{
if (l >= r) return k*l;
int mid = (l+r)/2;
if (sz[rs[root1]]+sz[rs[root2]] >= k) return query(rs[root1],rs[root2],mid+1,r,k);
return f[rs[root1]]+f[rs[root2]]+query(ls[root1],ls[root2],l,mid,k-sz[rs[root1]]-sz[rs[root2]]);
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
rt[i] = update(rt[i-1],1,n,a[i]);
}
for (int i = 1; i <= m; i++)
{
int x,l,r;
cin >> x >> l >> r;
RT = updateq(RT,1,n,x);
cout << query(rt[r],RT,1,n,r)-query(rt[l-1],RT,1,n,l-1) << '\n';
}
return 0;
}