bzoj 1604

前置技能:曼哈顿距离转切比雪夫距离

曼哈顿距离:已知两点$A(x_{1},y_{1})$,$B(x_{2},y_{2})$,则其曼哈顿距离为$|x_{2}-x_{1}|+|y_{2}-y_{1}|$

切比雪夫距离:已知两点$A(x_{1},y_{1})$,$B(x_{2},y_{2})$,则其切比雪夫距离为$max(|x_{2}-x_{1}|,|y_{2}-y_{1}|)$

二者的转化:

已知两点$A(x_{1},y_{1})$,$B(x_{2},y_{2})$,设$A^{'}(x_{1}+y_{1},x_{1}-y_{1})$,$B^{'}(x_{2}+y_{2},x_{2}-y_{2})$

则$AB$两点的曼哈顿距离与$A^{'}B^{'}$之间的切比雪夫距离相等

证明显然

因此我们对每个点$P_{i}(x_{i},y_{i})$,构造一个新的点$P_{i}^{'}(x_{i}+y_{i},x_{i}-y_{i})$,这样我们只研究新点之间的切比雪夫距离即可

为什么我们要这样做?

这样的话我们就可以分别处理$x$和$y$了

我们把所有的新点按照$x$进行排序,然后维护一个$set$里存原先的$y$

从小向大枚举$x$,每枚举到一个$x$就先把之前x不合法的部分从set里删除,再在set里面查这个$y$的前驱后继,如果合法就连边(注意只想前驱后继连边即可,用并查集维护),再把y插入set中即可

这样做的合理性在于,显然连的所有边都是合法的,而且根据传递性只需相邻的连边就能维护一个完整的集合了

这样代码就很好写了

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#define ll long long
using namespace std;
struct node
{
    ll x,y;
    friend bool operator < (node a,node b)
    {
        return a.x==b.x?a.y<b.y:a.x<b.x;
    }
}p[100005];
int n,C;
int f[100005],siz[100005];
int findf(int x)
{
    return x==f[x]?x:f[x]=findf(f[x]);
}
struct Info
{
    ll y;
    int num;
    friend bool operator < (Info a,Info b)
    {
        return a.y==b.y?a.num<b.num:a.y<b.y;
    }
};
set <Info> S;
template <typename T>inline void read(T &x)
{
    T f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x=c*f;
}
void merge(int x,int y)
{
    int f1=findf(x),f2=findf(y);
    if(f1!=f2)f[f2]=f1,siz[f1]+=siz[f2];
}
int main()
{
    read(n),read(C);
    for(int i=1;i<=n;i++)
    {
        ll rx,ry;
        read(rx),read(ry);
        p[i].x=rx+ry,p[i].y=rx-ry;
        f[i]=i,siz[i]=1;
    }
    sort(p+1,p+n+1);
    int las=1;
    S.insert((Info){-0x3f3f3f3f3f3f3f3fll,0}),S.insert((Info){0x3f3f3f3f3f3f3f3fll,0});
    S.insert((Info){p[1].y,1});
    for(int i=2;i<=n;i++)
    {
        while(p[i].x-p[las].x>C&&las<i)S.erase((Info){p[las].y,las}),las++;
        set <Info>::iterator it1;
        it1=S.lower_bound((Info){p[i].y,0});
        if(it1!=S.end()&&abs(p[i].y-(*it1).y)<=C)merge(i,(*it1).num);
        it1--;
        if(it1!=S.end()&&abs(p[i].y-(*it1).y)<=C)merge(i,(*it1).num);
        S.insert((Info){p[i].y,i});

    }
    int cnt=0,ans=0;
    for(int i=1;i<=n;i++)if(f[i]==i)cnt++,ans=max(ans,siz[i]);
    printf("%d %d
",cnt,ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zhangleo/p/11082532.html