ZOJ 3726 Alice's Print Service 二分+rmq

        打印k页的资料,给出n中付费方案,一次打印超过s1但不超过s2的每页收费p1,超过s2不超过s3的收费p2.....数据保证0=s1<s2<...<sn,p1>=p1>=p3>=...>=pn。接下来m个查询,对于每个查询问最少花多少钱?例如s1=0 s2=100  p1=20 p2=10 的时候,若要打印99页,显然直接打印100页要更便宜一点..所以结果是1000..

        由于数据该要求的都要求了,对于每个查询q,二分找到最大的si使q>=si,这样最少的费用要么是q*si,要么是sj*pj(i<j<=n),由于后面的sj*pj是确定的,要解决的就只是一个区间最小值的问题了..RMQ,线段树之类的随便搞一下就行了,当然也可以提前预处理一下,二分出si后可以O(1)直接出结果....我这写了一个单点更新区间查询的线段树.....

       

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <stack>
#include <queue>
#include <cstring>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
typedef long long ll;
const ll inf=(1LL<<60);
int n,m;
int tt;
struct node
{
    ll s;
    ll p;
    ll b;
    bool operator<(const node &tp)const
    {
        return b<tp.b;
    }
}a[120000];
struct SGT
{
    ll dt[480000];
   void pushup(int id)
   {
       dt[id]=min(dt[id<<1],dt[id<<1|1]);
   }
   void build(int id,int l,int r)
   {
       if (l==r)
       {
           dt[id]=(1LL<<62);
           return ;
       }
       int m=(l+r)>>1;
       build(lson);
       build(rson);
       pushup(id);
   }
   void modify(int id,int l,int r,int pos,ll c)
   {
       if (l==r)
       {
           dt[id]=c;
           return;
       }
       int m=(l+r)>>1;
       if (pos<=m) modify(lson,pos,c);
       else modify(rson,pos,c);
       pushup(id);
   }
   ll query(int id,int l,int r,int L,int R)
   {
       if (l==L && r==R)
       {
           return dt[id];
       }
       int m=(l+r)>>1;
       ll res=inf;
       if (R<=m) res=query(lson,L,R);
       else if (L>m) res=query(rson,L,R);
       else res=min(query(lson,L,m),query(rson,m+1,R));
       return res;
   }
}sgt;
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d",&n,&m);
        for (int i=1; i<=n; i++)
        {
            scanf("%lld%lld",&a[i].s,&a[i].p);
            a[i].b=(ll)(a[i].s*(ll)a[i].p);
        }
        sgt.build(1,1,n);
        for (int i=1; i<=n; i++)
        {
            sgt.modify(1,1,n,i,a[i].b);
        }
        ll tmp;
        ll ans=0;
        for (int i=1; i<=m; i++)
        {
            scanf("%lld",&tmp);
            int l=1,r=n+1;
            int mid;
            if (l!=r)
            {
                while (l<r)
                {
                    mid=(l+r)>>1;
                    if (a[mid].s>tmp)  r=mid;
                    else l=mid+1;
                }
                ans=tmp*a[l-1].p;
                if (l<=n) ans=min(ans,sgt.query(1,1,n,l,n));
            }
            else ans=tmp*a[l].p;
            printf("%lld\n",ans);
        }

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值