题解 P7564 【[JOISC 2021 Day3] ボディーガード】
题意
有
一个保镖保护一个人需要跟一个人一起逛街(即相同时刻在相同位置),跟着
有
数据范围:
solution
首先转化问题,把时间和位置作为两维,在坐标系中画出所有逛街的人的图像,即起点为
现在所有的线段都是与直线
注意到
现在剩下的问题就是走到格点之前的部分,一个保镖的策略是:要么一直往上走,找到一个合适的横着的线段,跟着走一段,到达格点;要么一直往右走,找到一个合适的竖着的线段,跟着走一段,到达格点。跟着走一段,然后获得格点的贡献是一个一次函数
具体的,枚举是往上走还是往右走,以往上走为例。找出初始位置在两个格线
时间复杂度是
#include <bits/stdc++.h>
using namespace std;
namespace iobuff{//输入输出量较大,输入输出优化
const int LEN=1000000;
char in[LEN+5],out[LEN+5];
char *pin=in,*pout=out,*ed=in,*eout=out+LEN;
inline char gc(void){
return pin==ed&&(ed=(pin=in)+fread(in,1,LEN,stdin),ed==in)?EOF:*pin++;
}
inline void pc(char c){
pout==eout&&(fwrite(out,1,LEN,stdout),pout=out);
(*pout++)=c;
}
inline void flush(){fwrite(out,1,pout-out,stdout),pout=out;}
template<typename T> inline void read(T &x){
static int f;
static char c;
c=gc(),f=1,x=0;
while(c<'0'||c>'9') f=(c=='-'?-1:1),c=gc();
while(c>='0'&&c<='9') x=10*x+c-'0',c=gc();
x*=f;
}
template<typename T> inline void putint(T x,char div='\n'){
static char s[20];
static int top;
top=0;
x<0?pc('-'),x=-x:0;
while(x) s[top++]=x%10,x/=10;
!top?pc('0'),0:0;
while(top--) pc(s[top]+'0');
pc(div);
}
}
using namespace iobuff;
const int N=5605,Q=3e6+5;
#define ll long long
#define int ll
#define y1 Yy1
#define y2 Yy2
template<int T> struct lsh{//离散化
int buc[T],tot;
inline void ins(int x){buc[++tot]=x;}
inline void build(){
sort(buc+1,buc+1+tot);
tot=unique(buc+1,buc+1+tot)-buc-1;
}
inline int operator ()(int x){return lower_bound(buc+1,buc+1+tot,x)-buc;}
inline int operator [](int x){return buc[x];}
};
lsh<N> bx,by;
lsh<Q> qry;
int qx[Q],qy[Q];
namespace SGT{//李超树
#define lid (id<<1)
#define rid (id<<1|1)
#define mid ((l+r)>>1)
int k[Q<<2];ll b[Q<<2];
void build(int id,int l,int r){
k[id]=0;b[id]=-1;
if(l==r)return;
build(lid,l,mid);build(rid,mid+1,r);
}
inline ll calc(int id,int x){return 1ll*k[id]*x+b[id];}
inline ll calc(int _k,ll _b,int x){return 1ll*_k*x+_b;}
void insert(int id,int l,int r,int _k,ll _b){
if(b[id]==-1){k[id]=_k;b[id]=_b;return;}
if(calc(id,qry[mid])<calc(_k,_b,qry[mid]))swap(k[id],_k),swap(b[id],_b);
if(l==r)return;
if(calc(id,qry[r])<calc(_k,_b,qry[r]))insert(rid,mid+1,r,_k,_b);
if(calc(id,qry[l])<calc(_k,_b,qry[l]))insert(lid,l,mid,_k,_b);
}
ll query(int id,int l,int r,int pos){
if(b[id]==-1)return 0;
if(l==r)return calc(id,qry[pos]);
return max(calc(id,qry[pos]),pos<=mid?query(lid,l,mid,pos):query(rid,mid+1,r,pos));
}
}
ll val[N][N];
int vx[N][N],vy[N][N];
template<typename T> inline void Max(T &a,T b){if(a<b)a=b;}
struct Line{
int x1,x2,y1,y2,c;
Line(int _x1=0,int _y1=0,int _x2=0,int _y2=0,int _c=0){x1=_x1;y1=_y1;x2=_x2;y2=_y2;c=_c;}
inline void build(){
x1=bx(x1);x2=bx(x2);y1=by(y1);y2=by(y2);
}
}line[N];
vector<int> bucx[N],bucy[N];
int n,q;
void init(){
bx.build();by.build();
for(int i=1;i<=n;++i){
line[i].build();//vx,vy 表示 (i,j) 向右走到 (i+1,j)/向上走到 (i,j+1) 的最大的 c
if(line[i].x1==line[i].x2){
for(int j=line[i].y1;j<line[i].y2;++j)
Max(vy[line[i].x1][j],line[i].c);
}else{
for(int j=line[i].x1;j<line[i].x2;++j)
Max(vx[j][line[i].y2],line[i].c);
}
}
for(int i=bx.tot;i;--i)for(int j=by.tot;j;--j)
val[i][j]=max(i<bx.tot?val[i+1][j]+1ll*vx[i][j]*(bx[i+1]-bx[i]):0ll,j<by.tot?val[i][j+1]+1ll*vy[i][j]*(by[j+1]-by[j]):0ll);
}
inline bool cmpx(int x,int y){return qx[x]>qx[y];}
inline bool cmpy(int x,int y){return qy[x]>qy[y];}
ll ans[Q];
signed main(){
read(n);read(q);
for(int i=1,a,b,t,c,x1,y1,x2,y2;i<=n;++i){
read(t);read(a);read(b);read(c);
x1=t;y1=a;
x2=t+abs(a-b);y2=b;
line[i]=Line(x1-y1,x1+y1,x2-y2,x2+y2,c>>1);
bx.ins(x1-y1);bx.ins(x2-y2);
by.ins(x1+y1);by.ins(x2+y2);
}
init();
for(int i=1,t,a;i<=q;++i){
read(t);read(a);
qx[i]=t-a;qy[i]=t+a;
bucx[bx(qx[i])].push_back(i);
bucy[by(qy[i])].push_back(i);
}
for(int i=1;i<=bx.tot;++i){
if(!bucx[i].size())continue;
qry.tot=0;
sort(bucx[i].begin(),bucx[i].end(),cmpy);
for(int x:bucx[i])qry.ins(bx[i]-qx[x]);
qry.build();
int R=qry.tot;
SGT::build(1,1,R);
int flag=by.tot;
for(int id:bucx[i]){
while(flag&&by[flag]>=qy[id]){
SGT::insert(1,1,R,vx[i-1][flag],val[i][flag]);
--flag;
}
Max(ans[id],SGT::query(1,1,R,qry(bx[i]-qx[id])));
}
}
for(int i=1;i<=by.tot;++i){
if(!bucy[i].size())continue;
qry.tot=0;
sort(bucy[i].begin(),bucy[i].end(),cmpx);
for(int x:bucy[i])qry.ins(by[i]-qy[x]);
qry.build();
int R=qry.tot;
SGT::build(1,1,R);
int flag=bx.tot;
for(int id:bucy[i]){
while(flag&&bx[flag]>=qx[id]){
SGT::insert(1,1,R,vy[flag][i-1],val[flag][i]);
--flag;
}
Max(ans[id],SGT::query(1,1,R,qry(by[i]-qy[id])));
}
}
for(int i=1;i<=q;++i)putint(ans[i]);
flush();
return 0;
}