P6007 [USACO20JAN]Springboards G
\(\color{purple}\text{P6007 [USACO20JAN]Springboards G}\)
题意
你从 \((0,0)\) 出发,到达 \((n,n)\) ,每次只能向上或向右走,有 \(m\) 个传送门,将你传送到传送门起点右上方的一个终点。求最少走路次数。
解法
我们不走传送门的时候答案就是 \(2n\) ,走了一个传送门从 \((sx,sy)\) 到 \((ex,ey)\) 后,答案就变成 \(2n-[(ex-sx)+(ey-sy)]\)。
我们把每个传送门看做一个点,把终点和起点的曼哈顿距离看作点权,答案就是 \(2n-max(\sum 经过的传送门点权)\)。
设 \(f[i]\) 表示到达第 \(i\) 个传送门时的点权最大值,状态转移方程: \(f[i]=max(f[i],f[j]+val[i]),ex[j]<=sx[i],ey[j]<=sy[i]\) 。
两维的限制条件,显然可以用树状数组维护 \(y\) 的值,我们需要保证更新 \(i\) 时,全部且仅有 \(ex[j]<=sx[i]\) 的点 \(j\) 被扔入树状数组。
我的第一思路是双指针,用 \(i\) 表示更新到第几个值,用 \(j\) 表示扔进树状数组的值到了第几个,但普通的双指针是不行的,因为 \(ex\) 和 \(sx\) 不一定同时单调递增。
所以正确的解法是:开两个数组,一个按照 \(sx\) 排序,用来表示求答案的顺序,另一个按照 \(ex\) 排序,用来丢进树状数组,可以证明,每次用到第二个数组的点时,它已经被更新过了。
解题过程
刚开始把一堆 \(m\) 写成 \(n\) ,一直错,然后因为使用第一思路只有 \(46pts\) ,用第一篇题解对拍出来的结果令我困扰许久,然后我又用第二篇,第三篇,最后发现题解很多都有问题。辗转半天,终于通过了这道题。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int read(){
int x=0,f=1;char c=getchar();
while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
struct POS{
int sx,sy,ex,ey,val,id;
}p[N],p2[N];
int n,m,C[N*3];
int lshx[N*2],lshy[N*2];
int mx,my,dis[N];
bool cmp(POS A,POS B){
return A.ex==B.ex?A.ey<B.ey:A.ex<B.ex;
}
bool cmp2(POS A,POS B){
return A.sx==B.sx?A.sy<B.sy:A.sx<B.sx;
}
void update(int u,int x){
for(int i=u;i<=my;i+=i&(-i))C[i]=max(C[i],x);
return;
}
int query(int u){
int res=0;
for(int i=u;i>0;i-=i&(-i))res=max(res,C[i]);
return res;
}
void LSH(){
sort(lshx+1,lshx+2*m+1);
sort(lshy+1,lshy+2*m+1);
mx=unique(lshx+1,lshx+2*m+1)-lshx-1;
my=unique(lshy+1,lshy+2*m+1)-lshy-1;
for(int i=1;i<=m;i++){
p[i].sx=lower_bound(lshx+1,lshx+mx+1,p[i].sx)-lshx;
p[i].ex=lower_bound(lshx+1,lshx+mx+1,p[i].ex)-lshx;
p[i].sy=lower_bound(lshy+1,lshy+my+1,p[i].sy)-lshy;
p[i].ey=lower_bound(lshy+1,lshy+my+1,p[i].ey)-lshy;
}
return;
}
signed main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=m;i++){
p[i].id=i;
p[i].sx=read(),p[i].sy=read();
lshx[2*i-1]=p[i].sx,lshy[2*i-1]=p[i].sy;
p[i].ex=read(),p[i].ey=read();
lshx[2*i]=p[i].ex,lshy[2*i]=p[i].ey;
p[i].val=(p[i].ex-p[i].sx)+(p[i].ey-p[i].sy);
}
LSH();
for(int i=1;i<=m;i++)p2[i]=p[i];
sort(p+1,p+m+1,cmp);
sort(p2+1,p2+m+1,cmp2);
for(int i=1,j=1;i<=m;i++){
while(j<i && p[j].ex<=p2[i].sx){update(p[j].ey,dis[p[j].id]);j++;}
dis[p2[i].id]=query(p2[i].sy)+p2[i].val;
}
int ans=0;
for(int i=1;i<=m;i++)ans=max(ans,dis[i]);
printf("%lld\n",n*2-ans);
return 0;
}
/*
3 5
2 3 2 5
4 0 9 2
0 0 1 3
5 2 10 4
4 0 4 0
5 5
2 3 5 4
1 4 5 8
2 3 2 3
1 2 3 6
0 1 1 5
5 5
1 3 1 4
0 1 0 1
0 0 1 1
1 0 1 0
1 2 1 3
*/

浙公网安备 33010602011771号