玲珑杯1151 - Delivering parcels(主席树)

本文介绍了一种解决特定物品分配问题的方法,通过将物品按权重降序排列,并使用线段树进行更新和查询操作,来优化寻找两个集合中最大权重与价值乘积之和的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址
题意:有2*n个物品均分给两个人,物品有两个属性w和v,求俩人物品中max(w)*max(v)的和。
题解:
将物品按w降序排序,则物品1一定属于第一组,枚举2—n,将它们分到第二组,然后枚举最大的v在第一组和第二组的情况,维护一个前缀最大可以减少使用query的次数。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<int,int>pa;
const int N=2e5+10;
const int mod=1e9+7;
const ll INF=1e18;
const int inf=1e4;
int read()
{
    int x=0;
    char ch = getchar();
    while('0'>ch||ch>'9')ch=getchar();
    while('0'<=ch&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x;
}
/***********************************************************/
struct node
{
    int l,r,sum;
} T[N*20];
struct noder
{
    int w,v;
} a[N];
bool cmp(noder x,noder y)
{
    return x.w>y.w;
}
int mxv[N];
int mxvr[N];
int root[N];
int cnt,n;
void update(int l,int r,int &x,int y,int pos)
{
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r) return ;
    int mid=(r+l)>>1;
    if(mid>=pos)
        update(l,mid,T[x].l,T[y].l,pos);
    else
        update(mid+1,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int x,int y,int k)
{
    if(l==r) return l;
    int mid=(r+l)>>1;
    int sum=T[T[y].l].sum-T[T[x].l].sum;
    if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);
    else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}
void init()
{
    cnt=0;
    mxv[0]=0;
    mxvr[2*n+1]=0;
}
int main()
{
    scanf("%d",&n);
    init();
    for(int i=1; i<=2*n; i++) scanf("%d",&a[i].w);
    for(int i=1; i<=2*n; i++) scanf("%d",&a[i].v);
    sort(a+1,a+1+2*n,cmp);
    for(int i=1; i<=2*n; i++)
    {
        mxv[i]=max(mxv[i-1],a[i].v);
        update(1,2*n,root[i],root[i-1],a[i].v);
    }
    for(int i=2*n; i>=1; i--) mxvr[i]=max(mxvr[i+1],a[i].v);
    ll ans=INF;
    ans=min(ans,(ll)a[1].w*mxv[n]+(ll)a[n+1].w*mxvr[n+1]);
    for(int i=2; i<=n; i++)
    {
        ll x=query(1,2*n,root[i],root[2*n],n-1);
        ll y=query(1,2*n,root[i],root[2*n],n-i+1);
        ans=min(ans,(ll)a[1].w*max(mxv[i-1],mxvr[i+1])+(ll)max(x,(ll)a[i].v)*a[i].w);
        ans=min(ans,(ll)a[1].w*max((ll)mxv[i-1],y)+(ll)a[i].w*mxvr[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值