ARC065C

曼哈顿距离和切比雪夫距离,一般出现了其中一个就要去想想是不是可以转换成另一个。
本题就是一个典型的例子,在曼哈顿距离下会比较麻烦——每次可以转移到的点都是一个斜着的正方形,不方便枚举。
而转换成了切比雪夫距离之后就变成了一个正着的正方形了。

不难发现,无论怎么操作,每个点对之间的距离(无论是曼哈顿还是切比雪夫)都是不变的。
因此,在转换成了切比雪夫距离之后,只要知道了最终可以到达的集合 \(p\) 中有哪些点,答案就是所有以这些点为几何中心,边长为 \(2dis\) 的正方形的边上的点的个数之和。
形式化地说,有 \( \begin{aligned} ans&=\sum^{}_{i\in p} \sum^{n}_{j=1} ([x_{j}=x_{i}+dis,|y_{i}-y_{j}|\leq dis]+[x_{j}=x_{i}+dis,|y_{i}-y_{j}|\leq dis]+[x_{j}=x_{i}+dis,|y_{i}-y_{j}|\leq dis]+[x_{j}=x_{i}+dis,|y_{i}-y_{j}|\leq dis]) \end{aligned} \)
这个东西可以用动态开点线段树维护,只需要支持单点插入和区间询问,比较好写,不过要记得特判一下正方形的四个角,否则会被算两次,特判方法可以看代码。
这里的时间复杂度是 \(O(n \log n)\)

接下来是解决如何得到集合 \(p\) 了。其实这个也不难,可以离散化,对每一个 \(x\) 开一个 set,然后做一次 bfs ,直接暴力地去正方形四条边上找,把遍历到的点全部删掉。
因为每一个点只会被删除一次,因此这个地方的时间复杂度也是 \(O(n \log n)\)

最后记得答案要除以二,因为点对是无序的,上面计算的过程中每一个点对都被统计了两次。

Code
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
    bool f=true;ll x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    if(f) return x;
    return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
const int MAXN=1e5+7;
struct node
{
    ll x,y;
}p[MAXN];
#define pll pair<ll,ll>  
int n,a,b;
int mark[MAXN];
ll dis,ans;
#define IT set<pll>::iterator
struct seg
{
    struct T
    {
        int c[2],sum;
    }t[MAXN<<8];
    #define mid (L+R>>1)
    #define lc t[u].c[0]
    #define rc t[u].c[1]
    int cnt;
    void update(int u){
        t[u].sum=0;
        if(lc) t[u].sum+=t[lc].sum;
        if(rc) t[u].sum+=t[rc].sum;
    }
    void insert(int &u,int pos,ll L=-2e9,ll R=2e9){
        if(!u) u=++cnt;
        if(L==pos&&R==pos){
            t[u].sum=1;
            return;
        }
        if(pos<=mid) insert(lc,pos,L,mid);
        else insert(rc,pos,mid+1,R);
        update(u);
    }
    ll query(int u,int l,int r,ll L=-2e9,ll R=2e9){
        if(!u||l>r) return 0;
        if(L==l&&R==r) return t[u].sum;
        if(r<=mid) return query(lc,l,r,L,mid);
        else if(l>mid) return query(rc,l,r,mid+1,R);
        else return (query(lc,l,mid,L,mid)+query(rc,mid+1,r,mid+1,R));
    }
    #undef lc
    #undef rc
    #undef mid
}T[2];
int root[2][MAXN<<2];
int cnt;
#define pll pair<ll,ll>
#define IT set<pll>::iterator
set<pll> f[2][MAXN<<2];
map<int,int> id[2];
int main(){
    n=read(),a=read(),b=read();
    for(ri i=1;i<=n;++i){
        ll x=read(),y=read();
        p[i].x=x+y,p[i].y=x-y;
        if(!id[0].count(p[i].x)) id[0][p[i].x]=++cnt;
        T[0].insert(root[0][id[0][p[i].x]],p[i].y);
        f[0][id[0][p[i].x]].insert((pll){p[i].y,i});
        if(!id[1].count(p[i].y)) id[1][p[i].y]=++cnt;
        T[1].insert(root[1][id[1][p[i].y]],p[i].x);
        f[1][id[1][p[i].y]].insert((pll){p[i].x,i});
    }
    dis=max(abs(p[a].x-p[b].x),abs(p[a].y-p[b].y));
    queue<int> q;
    q.push(a),q.push(b);
    while(!q.empty()){
        int u=q.front();q.pop();
        if(mark[u]) continue;
        mark[u]=1;
        if(id[0].count(p[u].x+dis)){
            int now=id[0][p[u].x+dis];
            ans+=T[0].query(root[0][now],max(-2e9,p[u].y-dis),min(2e9,p[u].y+dis));
            set<pll> &s=f[0][now];
            for(IT it=s.lower_bound((pll){p[u].y-dis,0});it!=s.end()&&abs(it->first-p[u].y)<=dis;it=s.erase(it)) q.push(it->second);
        }
        if(id[0].count(p[u].x-dis)){
            int now=id[0][p[u].x-dis];
            ans+=T[0].query(root[0][now],max(-2e9,p[u].y-dis),min(2e9,p[u].y+dis));
            set<pll> &s=f[0][now];
            for(IT it=s.lower_bound((pll){p[u].y-dis,0});it!=s.end()&&abs(it->first-p[u].y)<=dis;it=s.erase(it)) q.push(it->second);
        }
        if(id[1].count(p[u].y+dis)){
            int now=id[1][p[u].y+dis];
            ans+=T[1].query(root[1][now],max(-2e9,p[u].x-dis+1),min(2e9,p[u].x+dis-1));
            set<pll> &s=f[1][now];
            for(IT it=s.lower_bound((pll){p[u].x-dis,0});it!=s.end()&&abs(it->first-p[u].x)<=dis;it=s.erase(it)) q.push(it->second);
        }
        if(id[1].count(p[u].y-dis)){
            int now=id[1][p[u].y-dis];
            ans+=T[1].query(root[1][now],max(-2e9,p[u].x-dis+1),min(2e9,p[u].x+dis-1));
            set<pll> &s=f[1][now];
            for(IT it=s.lower_bound((pll){p[u].x-dis,0});it!=s.end()&&abs(it->first-p[u].x)<=dis;it=s.erase(it)) q.push(it->second);
        }
    }
    print(ans>>1);
    return 0;
}
posted @ 2021-04-26 10:47  krimson  阅读(82)  评论(0)    收藏  举报