NOIP 模擬 $98\; \rm 序列$
阿新 • • 發佈:2021-11-14
題解
題解 \(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();}