P4876 [USACO14MAR] The Lazy Cow_Gold 懒惰的牛(金)
看到本题没有题解,于是来发一篇。
本题的题意是在平面上找到一个点,使距离这个点的曼哈顿距离不超过
我们把曼哈顿距离不超过
看着特别不爽,根本不好处理。
但是,如果我们能够让它长这样:
那么,就可以使用扫描线来维护,从而做到
我们把这两个图联系一下,看过洛谷日报#182 常用距离算法详解的都应该发现,这不就是曼哈顿距离转切比雪夫距离吗?
于是,我们就可以把坐标
当然,还有一些细节处理:
1、最好把新的坐标离散化,因为
2、我们可以发现,转化后的正方形的边长是
3、注意!如果有高度相同的两条边,一定要先处理下边(也就是加进去的边),因为如果有这种情况,同时在这两条边上的点的答案会被记录到两条边中,但是如果先处理上边,就只会被记录到一条边中,导致答案出错!这样,我们会得到样例没过却有81分的好成绩。
Update:原来代码的读入压行了,这里把它展开。
代码如下:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<utility>
#include<algorithm>
using namespace std;
#define res register int
//#define cccgift
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) //fread优化
char buf[1<<21],*p1=buf,*p2=buf;
namespace wode{
template<typename T>
inline void read(T &x) //快读
{
static char ch;bool f=1;
for(x=0,ch=getchar();!isdigit(ch);ch=getchar()) if(ch=='-') f=0;
for(;isdigit(ch);x=(x<<1)+(x<<3)+(ch^48),ch=getchar());x=f?x:-x;
}
template<typename T>
inline T max(T x,T y) {return x<y?y:x;}
template<typename T>
inline T min(T x,T y) {return x<y?x:y;}
template<typename T>
inline void chkmax(T &x,T y) {x=x<y?y:x;}
template<typename T>
inline void chkmin(T &x,T y) {x=x<y?x:y;}
}
using wode::read;using wode::chkmin;using wode::chkmax;
struct node{
int x,y,z,k;
bool operator <(const node &b)const {return x<b.x||(x==b.x&&k>b.k);} //先处理下边!
} a[200001];
int tot,dat[800001],ad[800001],len,b[200001],n,m,w,h,nn,t,xx,yy,k;
inline void spread(int q) {
if(ad[q]) {
ad[q<<1]+=ad[q],ad[q<<1|1]+=ad[q];
dat[q<<1]+=ad[q],dat[q<<1|1]+=ad[q];
ad[q]=0;
}
}
void change(int q,int l1,int r1,int l,int r,int k) {
if(r<l1||r1<l) return;
if(l<=l1&&r1<=r) {dat[q]+=k,ad[q]+=k;return;}
int mid=l1+r1>>1;spread(q);
change(q<<1,l1,mid,l,r,k),change(q<<1|1,mid+1,r1,l,r,k),dat[q]=wode::max(dat[q<<1],dat[q<<1|1]);
}
int main()
{
read(n),read(k),k<<=1;
for(res i=1;i<=n;++i) {
read(a[++len].k),read(xx),read(yy);
a[len].x=xx+yy,a[len].y=xx-yy;
b[len]=a[len].y;
++len,a[len].x=a[len-1].x+k,a[len].y=a[len-1].y;
b[len]=a[len].z=a[len-1].z=a[len-1].y+k;
a[len].k=-a[len-1].k;
}
// for(res i=1;i<=len;++i) printf("%d %d %d %d\n",a[i].k,a[i].x,a[i].y,a[i].z);
sort(b+1,b+1+len),nn=unique(b+1,b+1+len)-b-1;
// for(res i=1;i<=nn;++i) printf("%d ",b[i]);puts("");
for(res i=1;i<=len;++i) a[i].y=lower_bound(b+1,b+1+nn,a[i].y)-b,a[i].z=lower_bound(b+1,b+1+nn,a[i].z)-b; //把坐标离散化
// for(res i=1;i<=len;++i) printf("%d %d\n",a[i].y,a[i].z);
sort(a+1,a+1+len);
for(res i=1;i<=len;++i) change(1,1,nn,a[i].y,a[i].z,a[i].k),chkmax(tot,dat[1]); //最后的答案就是每一次扫描的最大值,详见窗口的星星那道题。
printf("%d\n",tot);
return 0;
}