Arthur and Table
题意
一个桌子有n个腿,每个腿都有一个高度,当且仅当最高的腿的数量大于桌子腿数量的一半时,桌子才是稳定的。特殊的是当只有一个腿时,桌子是稳定的,当有两个腿时两个腿必须都得是最高的,才稳定。
分析
这题其实和去年的牛客的一道砍树题一样的(但是我没想起来那题,当时看的题解,稍微改了一下代码,就交了印象不深刻。。。)
首先我们按照桌子腿的高度从小到大排序,然后枚举当前最高的高度。
大于当前高度的肯定都要删除掉,用一个suf后缀来维护。
我们知道当前高度的桌腿的数量,根据这个数量算出小于这个高度的我们要删除几个?x个
然后我们用一颗权值线段树维护桌腿的数量以及价值。
查询前x个最小的权值和,当前高度的花费就是suf[i+1]+query(x)。
代码
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-14;
struct note
{
int wei,val;
}arr[N];
bool cmp(note a,note b)
{
return a.wei<b.wei;
}
int suf[N];
struct tree
{
int num,sum;
}node[N];
void build(int rt,int l,int r)
{
node[rt].num=node[rt].sum=0;
if(l==r) return ;
int mid=(l+r)/2;
build(rt*2,l,mid);
build(rt*2+1,mid+1,r);
}
void pushup(int rt)
{
node[rt].num=node[rt*2].num+node[rt*2+1].num;
node[rt].sum=node[rt*2].sum+node[rt*2+1].sum;
}
void update(int rt,int l,int r,int pos)
{
if(l==r)
{
node[rt].num++;
node[rt].sum+=l;
return;
}
int mid=(l+r)/2;
if(pos<=mid) update(rt*2,l,mid,pos);
else update(rt*2+1,mid+1,r,pos);
pushup(rt);
}
int query(int rt,int l,int r,int k)
{
if(l==r) return k*l;
int lnum=node[rt*2].num;//左子树中桌腿数量
int mid=(l+r)/2;
if(k<=lnum) return query(rt*2,l,mid,k);
else return node[rt*2].sum+query(rt*2+1,mid+1,r,k-lnum);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&arr[i].wei);
for(int i=1;i<=n;i++)
scanf("%d",&arr[i].val);
sort(arr+1,arr+1+n,cmp);//按照高度从小到大排序
for(int i=n;i;i--)//计算后缀
suf[i]=suf[i+1]+arr[i].val;
int now,ans=inf;
build(1,1,200);
for(int i=1;i<=n;i++)
{
now=0;
int j=i;
while(j<=n&&arr[j].wei==arr[i].wei)//计算当前高度的桌腿的数量,下标
{
j++;
now++;
}
int x=max(i-now,0);//小于当前高度,要删去的数量
ans=min(ans,suf[j]+query(1,1,200,x));//计算贡献
for(int k=i;k<j;k++)//把当前高度更新如线段树
update(1,1,200,arr[k].val);
i=j-1;
}
printf("%d
",ans);
return 0;
}