Loading

ABC 306 E 题解

原题传送门

题意:带修维护序列前k大的和

首先性质:1、只关心值;2、k不变

一眼ds,且是排序类的。修改可以拆成插入和删除。一眼Treap。

然后再考虑k不变。我们发现每次修改我们在非前k大的数中其实只关心最大的一个,因为只有它有机会“进化”进入前k大。

所以直接拆成两个,前k大和其余的。

然后因为懒直接multiset不香吗

然后就结束了。

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define ll long long
const int N=500050;
multiset<int>A,B;
int n,k,q,a[N];
ll ans;
inline int read(){
    re int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
void print(){
	for(multiset<int>::iterator i=A.begin();i!=A.end();i++)cout<<*i<<' ';
	puts("");
	for(multiset<int>::iterator i=B.begin();i!=B.end();i++)cout<<*i<<' ';
	puts("");
}
int main(){
	cin>>n>>k>>q;
	for(re int i=1;i<=k;i++)A.insert(0);
	for(re int i=k+1;i<=n;i++)B.insert(0);
	for(re int j=1;j<=q;j++){
		int x=read(),y=read();
		y=-y;
		int val=a[x];
//		if(j==6){
//			for(re int i=1;i<=n;i++)cout<<a[i]<<' ';
//			puts("");
//			print();
//		}
		a[x]=y;
		multiset<int>::iterator fnd=A.find(val);
		
		if(fnd!=A.end()){
			ans-=val;
			
			A.erase(fnd);
			multiset<int>::iterator b=B.begin();
			//cout<<"BEGIN="<<*b<<endl;
			if(y<=*b){
				//puts("star");
				ans+=y,A.insert(y);
			}
			else{
				int bg=*b;
				A.insert(bg);
				ans+=bg;
				B.erase(b);
				B.insert(y);
			}
			
		}
		else{
			
			multiset<int>::iterator kp=B.find(val);
			if(kp==B.end()){
				//puts("star");
				//puts("!!!");
			}
			multiset<int>::iterator p=--A.end();
			B.erase(kp);
			
			
			if(*p<=y){
				//puts("star");
				B.insert(y);
			}
			else{
				ans-=*p;
				B.insert(*p);
				A.erase(p);
				ans+=y;
				A.insert(y);
				
			}
		}
		//print();
		printf("%lld\n",-ans);
		//puts("");
	}
    return 0;
}
posted @ 2023-08-11 16:14  MrcFrst  阅读(9)  评论(0编辑  收藏  举报