CF557C Arthur and Table の Solution

Link

对于大众来说权值线段树的入门题,一道写起来让我破防的题目。

首先很套路的固定最大值 xx,这时候考虑什么时候答案最小。

首先所有大于 xx 的腿我们要删掉,记这个和为 ss。其次发现,删掉长度等于 xx 的腿必然是不优的,因为删去了长度等于 xx 的腿代表我还要删掉更多长度小于 xx 的腿来满足条件。

假设长度为 xx 的腿有 lenlen 个,如果小于 xx 的腿的数量 plen1p\leq len-1 的话,说明不用删掉长度小于 xx 的腿就能满足条件,这时候算出 ss 是容易的。

如果 p>len1p>len-1 的话,这就说明我们需要删掉长度小于 xx 代价前 plen+1p-len+1 小的所有腿,如果我们从前往后扫值域的话,就发现我们还要会维护单点修改。

观察到 dd 很小,可以考虑权值线段树解决,维护对于每种代价出现的次数以及和,我们要找到前 plen+1p-len+1 小的话直接在上面做线段树二分就行。

找到对应位置以后剩下就是一个求和的事情了,写了两只 log\log 的劣解。

可能是太久没写OI了,前前后后写了很久,破防了。

#include<bits/stdc++.h>
using namespace std;
const int N =1e6+10;
struct node{
	int sum,num;
}d[N];
vector<int> g[N];
int l[N],D[N],n,sum,num,prelst,ans=INT_MAX,now,V=100000;
void update(int l,int r,int s,int t,int p){
	if(l<=s&&t<=r){
		d[p].num++,d[p].sum+=s;return ;
	}
	int mid=(s+t)>>1;
	if(l<=mid)	update(l,r,s,mid,p<<1);
	if(r>mid)	update(l,r,mid+1,t,p<<1|1);
	d[p].num=d[p<<1|1].num+d[p<<1].num,d[p].sum=d[p<<1|1].sum+d[p<<1].sum;
}
int Querynum(int l,int r,int s,int t,int p){
	if(l>r)	return 0;
	if(l<=s&&t<=r)	return d[p].num; 
	int mid=(s+t)>>1,ans=0;
	if(l<=mid)	ans+=Querynum(l,r,s,mid,p<<1);
	if(r>mid)	ans+=Querynum(l,r,mid+1,t,p<<1|1);
	return ans;
}
int Query(int s,int t,int p,int num){
	if(s==t)	return s;
	int mid=(s+t)>>1,ans=-1;
	if(Querynum(1,mid,1,200,1)>=num)	ans=Query(s,mid,p<<1,num);
	else if(Querynum(1,t,1,200,1)>=num)	ans=Query(mid+1,t,p<<1|1,num);
	return ans;
}
int Querysum(int l,int r,int s,int t,int p){
	if(l>r)	return 0;
	if(l<=s&&t<=r)	return d[p].sum;
	int mid=(s+t)>>1,ans=0;
	if(l<=mid)	ans+=Querysum(l,r,s,mid,p<<1);
	if(r>mid)	ans+=Querysum(l,r,mid+1,t,p<<1|1);
	return ans;
}
void Add(int x){
	for(int i=0;i<g[x].size();i++)	update(g[x][i],g[x][i],1,200,1);
	now+=g[x].size();
}
int main()
{
	int prelst1=0;
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>l[i];
	for(int i=1;i<=n;i++)	cin>>D[i],g[l[i]].push_back(D[i]),prelst+=D[i],prelst1+=D[i];
	for(int i=1;i<=V;i++){
		num=0,sum=0;
		if(g[i].size()==0)	continue;
		for(int j=0;j<g[i].size();j++)	prelst-=g[i][j];
		int len=g[i].size(),pre=len*2-1;
		if(now+g[i].size()<=pre){ans=min(ans,prelst),Add(i);continue;}
		if(g[i].size()==1){ans=min(ans,prelst1-g[i][0]),Add(i);continue;}
		int Q=Query(1,200,1,now-(pre-len));
		ans=min(ans,prelst+Querysum(1,Q-1,1,200,1)+(now+len-pre-Querynum(1,Q-1,1,200,1))*Q),Add(i);
	} 
	cout<<ans<<endl;
	return 0;
}
/*
10
20 1 15 17 11 2 15 3 16 3
129 114 183 94 169 16 18 104 49 146
*/
posted @   June_Failure  阅读(29)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示