APPLE buSinEss

题目描述

有一棵 n n n 个节点的完全二叉树,每个节点有 a i a_i ai 个苹果,有 m m m 个用户,每个人会购买一条路径 ( u i , v i ) (u_i,v_i) (ui,vi) 上的苹果,保证 u i u_i ui v i v_i vi 的祖先。第 i i i 个人最多买 c i c_i ci 个苹果,每个苹果支付 w i w_i wi 元。问最大付钱数,多测。

数据范围

n , m ≤ 1 0 5 ; ∑ n , ∑ m ≤ 1 0 6 ; w i ≤ 1 0 4 ; c i , a i ≤ 1 0 9 n,m \le 10^5;\sum n,\sum m \le 10^6;w_i \le 10^4;c_i,a_i\le 10^9 n,m105;n,m106;wi104;ci,ai109

题解

暴力的话费用流即可。

考虑费用流的过程,发现我们是 w i w_i wi 从大往小占用流量,贪心的想应该是先放在深度深的地方,然后当有新的 w i w_i wi 来的时候再为它让路。这个过程用 s e t set set 维护即可。由于树高不高,所以每个点只会拆出 l o g log log 个点,效率为 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

代码

#include <bits/stdc++.h>
#define LL long long
#define _(d) while(d(isdigit(c=getchar())))
using namespace std; const int N=1e5+5;
int Rd(){char c;_(!);int x=c^48;_()x=(x<<3)+(x<<1)+(c^48);return x;}
int T,n,m,a[N]; LL ans;
struct O{int u,v,c,w;}p[N];
bool cmp(O A,O B){return A.w>B.w;}
struct Q{
    int x,y;
    friend bool operator < (const Q& A,const Q& B){
        if (p[A.x].u==p[B.x].u) return A.x<B.x;
        return p[A.x].u<p[B.x].u;
    }
};
multiset<Q>s[N];
int ins(int x,int i,int c){
    if (x<p[i].u) return 0;
    int fl=0;
    if (a[x]){
        int v=min(a[x],c);
        a[x]-=v;c-=v;fl+=v;
        s[x].insert((Q){i,v});
    }
    if (c) for (Q u;;){
        u=*s[x].begin();
        if (p[u.x].u<p[i].u){
            s[x].erase(s[x].begin());
            int v=ins(x>>1,u.x,min(c,u.y));
            fl+=v;c-=v;if (v) s[x].insert((Q){i,v});
            if (v<u.y){
                s[x].insert((Q){u.x,u.y-v});break;
            }
            if (!c) break;
        }
        else break;
    }
    if (c) fl+=ins(x>>1,i,c);return fl;
}
void work(){
    n=Rd(),m=Rd();ans=0;
    for (int i=1;i<=n;i++)
        a[i]=Rd(),s[i].clear();
    for (int u,v,c,w,i=1;i<=m;i++)
        u=Rd(),v=Rd(),c=Rd(),w=Rd(),
        p[i]=(O){u,v,c,w};
    sort(p+1,p+m+1,cmp);
    for (int i=1;i<=m;i++)
        ans+=1ll*ins(p[i].v,i,p[i].c)*p[i].w;
    printf("%lld\n",ans);
}
int main(){
    for (T=Rd();T--;work());
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值