bzoj1560: [JSOI2009]火星藏宝图

时间:2023-03-10 03:07:58
bzoj1560: [JSOI2009]火星藏宝图

考虑到一个性质,A到B的距离一定不小于A到C再到B的距离,因为能够到达这三个点不可能构成锐角三角形

对于当前点的更新只需要找那些无法经过其它点再到当前点的点,相当于是一个y坐标单调减的上凸包,随便维护下

卡常让我迷失了心智

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int inf=(<<);
inline int sqr(int x){return x*x;}
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
} struct point{int x,y,d;}p[];
inline bool cmp(point p1,point p2){return p1.x==p2.x?p1.y<p2.y:p1.x<p2.x;}
inline int dis(int i,int j){return sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y);} int up[][];
int f[];
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
int n,m,k,i,j;
n=read(),m=read();
for(i=;i<=n;i++)
p[i].x=read(),p[i].y=read(),p[i].d=read();
sort(p+,p+n+,cmp);
for(i=;i<=n;i++)up[p[i].x][p[i].y]=i; for(j=m;j>=;j--)
for(i=;i<=m;i++)
if(!up[i][j])up[i][j]=up[i][j+]; f[]=p[].d; p[].y=inf;
for(i=;i<=n;i++)
{
k=;
f[i]=-inf; if( !(up[p[i].x][k]==i||p[up[p[i].x][k]].y>p[i].y) )
{
while(k<p[i].y&& !(up[p[i].x][k+]==i||p[up[p[i].x][k+]].y>p[i].y) )k=p[up[p[i].x][k+]].y; if(f[up[p[i].x][k]]!=-inf)
f[i]=max(f[i],f[up[p[i].x][k]]-dis(i,up[p[i].x][k])+p[i].d);
} for(j=p[i].x-;j>=;j--)//纵
{
if( !(p[up[j][k]].y>p[i].y) )
{
while(k<p[i].y&& p[up[j][k+]].y<=p[i].y )k=p[up[j][k+]].y; if(f[up[j][k]]!=-inf)
f[i]=max(f[i],f[up[j][k]]-dis(i,up[j][k])+p[i].d);
k++;
}
}
}
printf("%d\n",f[n]); return ;
}