【数据结构】【平衡树】【贪心】HDU6408 From ICPC to ACM

题意:

题意非常的鬼畜。。。
你经营着一家电脑公司,需要满足一些客户的需♂求。

每个月,你可以购买电脑配件(误),每单位价格为 c i
每个月需要制造 d i 台电脑,每制造一台电脑,需要一单位的电脑配件,然后外加 m i 的人工费。而且每个月最多制造 p i 台电脑。

然后电脑和配件都可以储存。
从第i个月存到第 i + 1 个月,最多储存 e i 台电脑,每储存一单位配件代价为 R i ,每储存一台电脑的代价为 E i

求满足所有条件的最小代价。(不能满足输出-1)

分析:

很简单的贪心模拟题。。。

然而我考场上写爆了、。。。一个最近经常犯的sb错误。。。更改变量后,想访问其原来的值,结果直接访问了更改后的。。。。

啊啊啊啊啊啊

其实真心水

一个贪心的思路:每次造电脑,都用之前的,代价最小的 d i 个。

因此要把之前的代价排序。。。

然而其实这个排序是一定的。(即可以预处理出来,不用一边模拟一边排序)

首先,由于配件是没有上限的,所以可以预处理得出:在每天造电脑用的配件的代价。这个很容易就能预处理出来,无非就是设当前最小的为 m i n p ,然后每一天和当天的 c i 取min,这一天后 m i n p + = R i

方便起见,可以把材料代价和造电脑的人力费 m i 合起来。

然后呢,再设当天的总代价为 m i + j = i , j < k E j

这样表示的话,在第x天出厂(给客户)时,要另外减去 j = x , j < k E j

这样有什么好处呢,很容易发现,因为减去的值只与出厂当天有关,所以这样一来每天造电脑的总代价就是一个定值了!

是个定值就可以直接排序了!

然后可以得到:在任意一天造电脑的代价排名。

现在只需要支持以下操作:找出当前存在的,代价最小的 d i 个值,找出当前存在的,代价最小的 e i 个值(后面的会被删去),以及有序插入每天的代价(以及当天能造出的电脑数)。

这不就是平衡树板题么。。。

每个节点存储:其代价,以及能制造的总数。还有其子节点全部制造完的总代价。

然后就可以水过去啦。。。。要注意 e i = 0 的时候要特判。。。

我的代码考场上为了卡常,对无解情况直接 O ( n ) 排出来,其实可以不用。。(考场上TLE是因为没有加 e i = 0 的特判)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 50010
using namespace std;
typedef long long ll;
ll c[MAXN],d[MAXN],p[MAXN],e[MAXN],m[MAXN],R[MAXN],E[MAXN];
int id[MAXN];
ll pre[MAXN];
pair<ll,ll> cost[MAXN];
int k;
struct node *NIL;
struct node{
    node *ch[2],*fa;
    ll val,sum,num,pri;
    ll hjb;
    bool Dir(){
        return this==fa->ch[1];
    }
    void setchild(node *x,int d){
        ch[d]=x;
        if(x!=NIL)
            x->fa=this;
    }
    void pushup(){
        //pushdown();
        //if(x->ch[0]!=NIL)x->ch[0]->pushdown();
        //if(x->ch[1]!=NIL)x->ch[1]->pushdown();
        totprice=ch[0]->totprice+ch[1]->totprice+pri*num;
        sum=ch[0]->sum+ch[1]->sum+num;
    }
}tree[MAXN],*root,*ncnt;
node * Newnode(node *x,int val){
    x->val=id[val];
    x->ch[0]=x->ch[1]=x->fa=NIL;
    x->sum=x->num=p[val];
    x->pri=pre[val]+m[val];
    x->totprice=x->pri*x->num;
    return x;
}
void Rotate(node *x){
    node *y=x->fa;
    //y->pushdown(),x->pushdown();
    int d=x->Dir();
    if(y==root)
        root=x,x->fa=NIL;
    else
        y->fa->setchild(x,y->Dir());
    y->setchild(x->ch[!d],d);
    x->setchild(y,!d);
    y->pushup();
}
void Splay(node *x,node *rt){
    //x->pushdown();
    while(x->fa!=rt){
        node *y=x->fa;
        if(y->fa==rt){
            Rotate(x);
            break;
        }
        if(x->Dir()==y->Dir())
            Rotate(y);
        else
            Rotate(x);
        Rotate(x);
    }
    x->pushup();
}
void Ins(node *&root,int val,int key){
    if(root==NIL){
        root=Newnode(++ncnt,key);
        return ;
    }
    node *y=root;
    int d;
    while(1){
        y->sum+=p[key];
        y->totprice+=p[key]*(pre[key]+m[key]);
        d=(y->val)<val;
        if(y->ch[d]==NIL)
            break;
        y=y->ch[d];
    }
    y->setchild(Newnode(++ncnt,key),d);
    y->pushup();
    Splay(y->ch[d],NIL);
}
void init(){
    for(int i=1;i<=k+1;i++)
        c[i]=d[i]=m[i]=p[i]=e[i]=R[i]=E[i]=pre[i]=0;
    root=NIL;
    ncnt=NIL;
}
node * find_kth(node *x,int k){
    if(x->ch[0]->sum >= k)
        return find_kth(x->ch[0],k);
    k-=x->ch[0]->sum;
    if(k<=x->num)
        return x;
    k-=x->num;
    return find_kth(x->ch[1],k);
}
bool check(){
    ll sumx=0;
    for(int i=1;i<=k;i++){
        sumx+=p[i];
        if(sumx<d[i])
            return 1;
        sumx-=d[i];
        sumx=min(sumx,e[i]);
    }
    return 0;
}
int main(){
    NIL=&tree[0];
    NIL->ch[0]=NIL->ch[1]=NIL->fa=NIL;
    root=ncnt=NIL;
    int t;
    SF("%d",&t);
    while(t--){
        SF("%d",&k);
        init();
        for(int i=1;i<=k;i++)
            SF("%I64d%I64d%I64d%I64d",&c[i],&d[i],&m[i],&p[i]);
        for(int i=1;i<k;i++)
            SF("%I64d%I64d%I64d",&e[i],&R[i],&E[i]);
        if(check()){
            PF("-1\n");
            continue;
        }
        ll minp=c[1];
        for(int i=1;i<=k;i++){
            minp=min(minp,c[i]);
            m[i]+=minp;
            minp+=R[i];
        }
        for(int i=k;i>=1;i--){
            pre[i]=pre[i+1]+E[i];
            cost[i]=make_pair(pre[i]+m[i],i);
        }
        sort(cost+1,cost+1+k);
        for(int i=1;i<=k;i++)
            id[cost[i].second]=i;
        ll ans=0;
        for(int i=1;i<=k;i++){
            if(p[i]!=0)
                Ins(root,id[i],i);
            if(d[i]!=0){
                node *x=find_kth(root,d[i]);
                Splay(x,NIL);

                ll res=x->ch[0]->totprice;
                ll d1=d[i];
                d[i]-=x->ch[0]->sum;
                x->ch[0]=NIL;
                res+=d[i]*x->pri;
                if(d[i]==x->num){
                    root=x->ch[1];
                    root->fa=NIL;
                }
                else{
                    x->num-=d[i];
                    x->pushup();
                }
                res-=pre[i]*d1;

                ans+=res;
            }
            if(i==k||root->sum <= e[i])
                continue;
            if(e[i]==0){
                root=ncnt=NIL;
                continue;
            }
            node *x=find_kth(root,e[i]);
            Splay(x,NIL);

            e[i]-=x->ch[0]->sum;
            x->num=e[i];
            x->ch[1]=NIL;
            x->pushup();
        }
        PF("%I64d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/81712292