[arc065e]Manhattan Compass

题目大意

不想讲。

做法

可以转45度角变成切比雪夫距离,这样图像是正方形。
先用bfs找出所有可以踩到的点(可以对每行每列维护set,一个被bfs到的直接在两颗平衡树中删去)。
然后对每个能被踩到的点统计与其切比雪夫距离为d的点的个数(可以对每行每列维护vector并二分)。
最后答案除以2。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
const ll inf=40000000000;
map<ll,int> row,col;
struct dong{
    int id,y;
    ll x;
    friend bool operator <(dong a,dong b){
        return a.x<b.x||a.x==b.x&&a.id<b.id;
    }
} zlt;
set<dong> ro[maxn],co[maxn];
set<dong>::iterator it;
vector<dong> rw[maxn],cl[maxn];
vector<dong>::iterator ti;
int x[maxn],y[maxn],dl[maxn];
ll p[maxn],q[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,xx,yy,a,b,head,tail,now,tot,top;
ll ans,d;
void del(int id){
    int xx=x[id],yy=y[id];
    zlt.id=id;zlt.x=q[yy];
    ro[xx].erase(ro[xx].find(zlt));
    zlt.id=id;zlt.x=p[xx];
    co[yy].erase(co[yy].find(zlt));
}
void ins(int x,ll l,ll r){
    int y;
    dong wxh;
    while (1){
        wxh.id=0;wxh.x=l;
        it=ro[x].lower_bound(wxh);
        if (it==ro[x].end()) break;
        zlt=*it;
        if (zlt.x>r) break;
        y=zlt.id;
        bz[y]=1;
        dl[++tail]=y;
        del(y);
    }
}
void inse(int x,ll l,ll r){
    int y;
    dong wxh;
    while (1){
        wxh.id=0;wxh.x=l;
        it=co[x].lower_bound(wxh);
        if (it==co[x].end()) break;
        zlt=*it;
        if (zlt.x>r) break;
        y=zlt.id;
        bz[y]=1;
        dl[++tail]=y;
        del(y);
    }
}
void ask(int x,ll l,ll r){
    /*int t=lower_bound(rw[x],rw[x]+s,r+1)-rw[x];
    t-=lower_bound(rw[x],rw[x]+s,l)-rw[x];*/
    dong wxh;
    wxh.id=0;wxh.x=r+1;
    zlt=*(lower_bound(rw[x].begin(),rw[x].end(),wxh));
    int t=zlt.y;
    wxh.id=0;wxh.x=l;
    zlt=*(lower_bound(rw[x].begin(),rw[x].end(),wxh));
    t-=zlt.y;
    ans+=(ll)t;
}
void query(int x,ll l,ll r){
    /*int s=cl[x].size();
    int t=lower_bound(cl[x],cl[x]+s,r+1)-cl[x];
    t-=lower_bound(cl[x],cl[x]+s,l)-cl[x];
    ans+=(ll)t;*/
    dong wxh;
    wxh.id=0;wxh.x=r+1;
    zlt=*(lower_bound(cl[x].begin(),cl[x].end(),wxh));
    int t=zlt.y;
    wxh.id=0;wxh.x=l;
    zlt=*(lower_bound(cl[x].begin(),cl[x].end(),wxh));
    t-=zlt.y;
    ans+=(ll)t;
}
int main(){
    scanf("%d%d%d",&n,&a,&b);
    fo(i,1,n){
        scanf("%d%d",&j,&k);
        p[i]=x[i]=j-k;
        q[i]=y[i]=j+k;
    }
    sort(p+1,p+n+1);
    tot=unique(p+1,p+n+1)-p-1;
    fo(i,1,n) x[i]=lower_bound(p+1,p+tot+1,x[i])-p;
    sort(q+1,q+n+1);
    top=unique(q+1,q+n+1)-q-1;
    fo(i,1,n) y[i]=lower_bound(q+1,q+top+1,y[i])-q;
    fo(i,1,tot) row[p[i]]=i;
    fo(i,1,top) col[q[i]]=i;
    d=max(abs(p[x[a]]-p[x[b]]),abs(q[y[a]]-q[y[b]]));
    fo(i,1,n){
        zlt.id=i;zlt.x=q[y[i]];
        ro[x[i]].insert(zlt);
        rw[x[i]].push_back(zlt);
        zlt.id=i;zlt.x=p[x[i]];
        co[y[i]].insert(zlt);
        cl[y[i]].push_back(zlt);
        /*rw[x[i]].push_back(q[y[i]]);
        cl[y[i]].push_back(p[x[i]]);*/
    }
    fo(i,1,tot){
        sort(rw[i].begin(),rw[i].end());
        zlt.id=0;zlt.x=inf;
        rw[i].push_back(zlt);
        t=rw[i].size();
        fo(j,0,t-1) rw[i][j].y=j;
    }
    fo(i,1,top){
        sort(cl[i].begin(),cl[i].end());
        zlt.id=0;zlt.x=inf;
        cl[i].push_back(zlt);
        t=cl[i].size();
        fo(j,0,t-1) cl[i][j].y=j;
    }
    head=0;
    dl[tail=1]=a;
    bz[a]=1;
    del(a);
    while (head<tail){
        now=dl[++head];
        xx=x[now];yy=y[now];
        if (row[p[xx]-d]) ins(row[p[xx]-d],q[yy]-d,q[yy]+d);
        if (row[p[xx]+d]) ins(row[p[xx]+d],q[yy]-d,q[yy]+d);
        if (col[q[yy]-d]) inse(col[q[yy]-d],p[xx]-d,p[xx]+d);
        if (col[q[yy]+d]) inse(col[q[yy]+d],p[xx]-d,p[xx]+d);
    }
    fo(i,1,n)
        if (bz[i]){
            xx=x[i];yy=y[i];
            if (row[p[xx]-d]) ask(row[p[xx]-d],q[yy]-d+1,q[yy]+d);
            if (col[q[yy]-d]) query(col[q[yy]-d],p[xx]-d,p[xx]+d-1);
            if (row[p[xx]+d]) ask(row[p[xx]+d],q[yy]-d,q[yy]+d-1);
            if (col[q[yy]+d]) query(col[q[yy]+d],p[xx]-d+1,p[xx]+d);
        }
    ans/=2;
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值