abc 282 e(mutiset维护第k小)

题目
题意: 计算数组中所有长度为m的子段的前k小个数的和。
思路: 先计算前m个数,然后在此基础上动态增删。
如果k=m,直接减一个数加一个数就行了。
否则的话,拿mutliset维护。
对于删除的数x,如果x<=第k小,减去x,然后维护第k小的指针右移,再加上新的第k小这个数。
对于插入的数y,如果y<=第k小,减去第k小,指针左移,再加上新插入的数y。
可以画几个圈圈表示前k小的数,然后看看删除或者插入一个数应该怎么变动,维护好前k小就好了。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int n,m,k,T;
int a[N];
multiset<int> sa; //维护第k小
ll sum = 0;
void solve()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=1;i<=m;++i) sa.insert(a[i]);
	auto lst = sa.begin();
	for(int cnt=k;cnt;--cnt,lst++)
	{
		sum += *lst;
	}
	lst--; 
	cout<<sum;
	for(int i=1;i+m<=n;++i)
	{
		if(k==m)
		{
			sum -= a[i];
			sum += a[i+m];
		}
		else
		{
			//删ai
			if(a[i]<=*lst)
			{
				sum -= a[i];
				lst++;
				sum += *lst;
			}
			sa.erase(a[i]);
			sa.insert(a[i+m]);
			if(a[i+m]<=*lst)
			{
				sum -= *lst;
				lst--;
				sum += a[i+m];
			}
		}
		cout<<" "<<sum;
	}
}
signed main(void)
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值