NOIP 模拟 $98\; \rm 序列$
题解 \(by\;zj\varphi\)
因为询问的区间要经过点 \(p\),所以可以拆成 \([l,p]\) 和 \([p+1,n]\) 两端。
对于前一段,相当于是求 \(suma_p-k\times sumb_p-\min(suma_l-k\times sumb_l)\),就是求
\[\max(k\times sumb_l-suma_l)(l\in [0,p-1])
\]
那么将每个前缀和看成一个斜率为 \(sumb\),截距为 \(suma\) 的直线。
将所有询问离线,从左往右依次加入所有直线,同时维护询问,后半段同理。
Code
#include<bits/stdc++.h>
#define ri signed
#define pd(i) ++i
#define bq(i) --i
#define func(x) std::function<x>
namespace IO{
char buf[1<<21],*p1=buf,*p2=buf;
#define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
#define dg1(x) std::cerr << #x"=" << x << ' '
#define dg2(x) std::cerr << #x"=" << x << std::endl
#define Dg(x) assert(x)
struct nanfeng_stream{
template<typename T>inline nanfeng_stream &operator>>(T &x) {
bool f=false;x=0;char ch=gc();
while(!isdigit(ch)) f|=ch=='-',ch=gc();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc();
return x=f?-x:x,*this;
}
}cin;
}
using IO::cin;
namespace nanfeng{
#define FI FILE *IN
#define FO FILE *OUT
template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
using ll=long long;
static const int N=1e6+7,bs=1e6+1;
int a,b,n,m,mk;
ll sma[N],smb[N],ans[N];
struct Que{int p,k,id;}que[N];
struct stra{ll k,b;}tmp;
auto calc=[](stra a,int x) {return a.k*x+a.b;};
auto cr=[](stra a,stra b) {return (1.0*(a.b-b.b))/(b.k-a.k);};
struct Seg{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
struct segmenttree{stra x;bool f;}T[N<<4];
void update(int x,int l,int r) {
if (!T[x].f) return T[x].f=true,T[x].x=tmp,void();
ll yl=calc(T[x].x,l-bs),yr=calc(T[x].x,r-bs),yyl=calc(tmp,l-bs),yyr=calc(tmp,r-bs);
if (yyl>=yl&&yyr>=yr) return T[x].x=tmp,void();
if (yyl<yl&&yyr<yr) return;
double p=cr(T[x].x,tmp)+bs;
int mid=(l+r)>>1;
if (yyl>=yl) {
if (p<=1.0*mid) update(ls(x),l,mid);
else {
stra tpm=tmp;
tmp=T[x].x;
T[x].x=tpm;
update(rs(x),mid+1,r);
}
} else {
if (p>1.0*mid) update(rs(x),mid+1,r);
else {
stra tpm=tmp;
tmp=T[x].x;
T[x].x=tpm;
update(ls(x),l,mid);
}
}
}
ll query(int x,int nx,int l,int r) {
ll res=LONG_LONG_MIN;
if (T[x].f) res=calc(T[x].x,nx-bs);
if (l==r) return res;
int mid=(l+r)>>1;
if (nx<=mid) res=cmax(res,query(ls(x),nx,l,mid));
else res=cmax(res,query(rs(x),nx,mid+1,r));
return res;
};
void clear(int x,int l,int r) {
T[x].f=false;
if (l==r) return;
int mid=(l+r)>>1;
clear(ls(x),l,mid),clear(rs(x),mid+1,r);
}
}T;
inline int main() {
FI=freopen("seq.in","r",stdin);
FO=freopen("seq.out","w",stdout);
cin >> n >> m;
for (ri i(1);i<=n;pd(i))
cin >> a >> b,sma[i]=sma[i-1]+a,smb[i]=smb[i-1]+b;
for (ri i(1);i<=m;pd(i)) {
cin >> que[i].p >> que[i].k;
que[i].id=i;
mk=cmax(mk,que[i].k);
}
const int lim=mk+bs;
std::sort(que+1,que+m+1,[](const Que &q1,const Que &q2) {return q1.p<q2.p;});
tmp={0,0};
T.update(1,1,lim);
int pnt=1;
for (ri i(1);i<=m;pd(i)) {
while(pnt<que[i].p) tmp={smb[pnt],-sma[pnt]},T.update(1,1,lim),++pnt;
ans[que[i].id]=T.query(1,que[i].k+bs,1,lim);
}
T.clear(1,1,lim);
pnt=n;
for (ri i(m);i;bq(i)) {
while(pnt>=que[i].p) tmp={-smb[pnt],sma[pnt]},T.update(1,1,lim),--pnt;
ans[que[i].id]+=T.query(1,que[i].k+bs,1,lim);
}
for (ri i(1);i<=m;pd(i)) printf("%lld\n",ans[i]);
return 0;
}
}
int main() {return nanfeng::main();}