打印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;
}