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