P9871 [NOIP2023] 天天爱打卡题解
Link
设
相当于枚举这段区间的左端点。
第一项与最后一项可以直接取最值,第三项只跟
但是跑步天数是
转移的时候要注意那个
注意转移顺序,
我在实现的时候把
特别注意,在扫描线的时候,两维都是可以离散化的,但在枚举其中一维的时候要记得这一维有没有离散化,我就因为两维都离散化但却在枚举的时候判断的是离散化前的数字导致第一组大样例过不去(
code
const int N=2e5+5;
int X[N],len;
//线段树实现了区间加,清空和区间查,为了美观不放上来了
struct upd{
ll l,r,x,w;
bool operator<(upd ano)const{
return x<ano.x;
}
}Q[N];
int tot;
ll f[N];
int x[N],y[N],w[N];
signed main(){
signed c=read(),_T=read();
while(_T--){
len=tot=0;
int n=read(),m=read(),k=read();ll d=read();
for(int i=1;i<=m;i++){
x[i]=read(),y[i]=read(),w[i]=read();
X[++len]=x[i],X[++len]=x[i]-y[i]+1;
}
sort(X+1,X+1+len);
len=unique(X+1,X+1+len)-X-1;
for(int i=1;i<=m;i++){
int l=lower_bound(X+1,X+1+len,x[i]-y[i]+1)-X;
int r=lower_bound(X+1,X+1+len,x[i])-X;
Q[++tot]={1,l,r,w[i]};//就是这里,r是要枚举的那一维,我在这里存的是离散化后的值,但在后面判断却用了离散化前的值
}
sort(Q+1,Q+1+tot);
for(int i=1,j=1;i<=len;i++){
int lst=lower_bound(X+1,X+1+len,X[i]-1)-X-1;
T.update(1,1,len,i,i,f[lst]+X[i]*d);//更新第i个点的贡献
while(j<=tot&&Q[j].x==i)//这里是Q[j].x==i而不是Q[j].x==X[i],就是上面说的离散化前与后的问题。
T.update(1,1,len,Q[j].l,Q[j].r,Q[j].w),j++;//扫描线
int frm=lower_bound(X+1,X+1+len,X[i]-k+1)-X;
f[i]=max(f[i-1],T.query(1,1,len,frm,i)-X[i]*d-d);//取最值
}print(f[len]),pc('\n');
T.init(1,1,len);
}
return 0;
}