ABC306 对顶堆 贡献法+DS

E

模拟 对顶堆

每次把序列里ax=ya_x=yax=y,问每次修改后序列的前k大?

k固定,但是带修改元素的前k大,考虑类似对顶堆的思路,维护两个set,第一个只存前k大,第二个存剩余元素。

每次修改,可以视为先删除,再插入,插入后还要考虑集合大小是否合法。具体来说,用一个数组记录每个元素在哪个集合里,如果修改的元素在前k大集合里,先删除,然后插入非前k大集合,这时前k大集合缺个元素,从非前k大集合里选最大的,插入。如果修改的在非前k大集合,先删除,再插入非前k大集合,然后把非前k大最大元素插入前k大,此时前k大集合元素多了一个,取出前k大里最小的插入非前k大

void solve(){
	int n,k,q;
	cin>>n>>k>>q;
	
	vector<int>a(n+1),vis(n+1);
	multiset<pair<int,int>>s[2];
	for(int i=1;i<=n;i++){
		if(i<=k){
			s[0].insert({a[i],i});
		}
		else{
			s[1].insert({a[i],i});
			vis[i]=1;
		}
	}
	int ans=0;
	auto add=[&](int x,int id)->void{
		vis[x]=id;
		if(id==0){
			ans+=a[x];
		}
		s[id].insert({a[x],x});
	};
	auto del=[&](int x,int id)->void{
		if(id==0){
			ans-=a[x];
		}	
		s[id].erase({a[x],x});
	};
	for(int i=1;i<=q;i++){
		int x,y;
		cin>>x>>y;
		
		if(vis[x]==0){
			del(x,0);
			a[x]=y;
			add(x,1);
			
			auto p=*s[1].rbegin();
			del(p.se,1);
			add(p.se,0);
		}
		else{
			del(x,1);
			a[x]=y;
			add(x,1);
			
			auto p=*s[1].rbegin();
			del(p.se,1);
			add(p.se,0);
			
			p=*s[0].begin();
			del(p.se,0);
			add(p.se,1);
		}
		
		cout<<ans<<'\n';
	}
}

F

贡献法 计数 ds

n个集合,两两组合,每个组合集合的权值为,把集合中元素排序,其中属于第一个集合的元素的下标和。问所有组合的权值和

考虑很多组合方案的权值和,但每个方案都是基本元素的贡献组成的,考虑贡献法,计算每个元素的贡献。

这就清晰了,一对集合组合,其中每个元素的贡献就等于两个集合中小于这个元素的元素个数。这可以推广,第iii个集合的一个元素xxx的贡献,等于所有[i+1,n][i+1,n][i+1,n]的集合中比它小的元素的个数,加上集合iii中比它小的元素个数×(n−i)×(n-i)×(ni)

枚举集合,计算贡献,然后加入/删除这个集合中的元素即可(取决于枚举顺序)

void solve(){
	int n,m;
	cin>>n>>m;
	
	vector<vector<int>>a(n+1,vector<int>(m+1));
	map<int,int>mp;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			mp[a[i][j]]++;
		}
	}
	int cnt=0;
	for(auto &[k,v]:mp){
		v=++cnt;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=mp[a[i][j]];
//			cout<<a[i][j]<<' ';
			add(a[i][j],1);
		}
//		cout<<'\n';
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			add(a[i][j],-1);
		}
		for(int j=1;j<=m;j++){
			ans+=ask(a[i][j]);
		}
		ans+=(n-i)*(1+m)*m/2;
	}
	cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值