题解:P2794 Facer和教官

题目链接


CDQ 分治的板子。

思路

先令 \(b_i\gets a_i-b_i\),则相似度就变成了 \(|b_i-b_j|+|a_i-a_j|\)。

考虑拆绝对值,对四个方向的点分别算贡献,设点 \(i\) 加入的时间为 \(t_i\),则点 \(j\) 能从左下方对 \(i\) 贡献的条件是:

\[\begin{cases} a_j\leq a_i\\ b_j\leq b_i\\ t_j<t_i\\ \end{cases} \]

它贡献的答案是 \(a_i+b_i-(a_j+b_j)\)。上面的贡献条件是一个三维偏序,所以可以直接套 CDQ 分治,先对时间轴分治,再对一维扫描线并维护另一维 \(a_j+b_j\) 的最大值。

其他三个方向也类似,跑四遍 CDQ 分治即可,时间复杂度 \(O((N+M)\log(N+M)\log V)\),其中 \(V\) 是 \(a\) 的值域。因为有四倍的常数,扫描线用线段树维护容易 TLE,建议将坐标加上 \(5\times 10^4+1\) 然后用树状数组维护。

代码

#include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define ll long long
const int N=1e5+5,P=1e9+7,sz=1e5+1,inf=1e9;

int n,m,k,ans[N];
struct opt
{
    int t,x,y,id;
}a[2*N];
vector<opt> b;

namespace bit
{
    int t[N];

    void init()
    {
        for(int i=1;i<=sz;i++)
            t[i]=-inf;
    }

    void update(int x,int y)
    {
        x+=5e4+1;
        while(x<=sz)
        {
            t[x]=max(t[x],y);
            x+=x&-x;
        }
    }

    void clear(int x)
    {
        x+=5e4+1;
        while(x<=sz)
        {
            t[x]=-inf;
            x+=x&-x;
        }
    }

    int getmax(int x)
    {
        x+=5e4+1;
        int y=-inf;
        while(x)
        {
            y=max(y,t[x]);
            x-=x&-x;
        }
        return y;
    }
}

void calc()
{
    sort(b.begin(),b.end(),[](opt u,opt v){return u.y==v.y?u.id<v.id:u.y<v.y;});
    for(auto p:b)
    {
        if(!p.id)
            bit::update(p.x,p.x+p.y);
        else
            ans[p.id]=min(ans[p.id],p.x+p.y-bit::getmax(p.x));
    }
    for(auto p:b)
        bit::clear(p.x);
}

void solve(int l,int r)
{
    if(l==r)
        return;
    int mid=(l+r)>>1;
    solve(l,mid);
    solve(mid+1,r);
    b.clear();
    for(int i=l;i<=mid;i++)
        if(!a[i].id)
            b.push_back(a[i]);
    for(int i=mid+1;i<=r;i++)
        if(a[i].id)
            b.push_back(a[i]);
    calc();
    for(auto &p:b)
        p.x*=-1;
    calc();
    for(auto &p:b)
        p.y*=-1;
    calc();
    for(auto &p:b)
        p.x*=-1;
    calc();
}

signed main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        a[i].t=i;
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].y=a[i].x-a[i].y;
    }
    for(int i=n+1;i<=n+m;i++)
    {
        a[i].t=i;
        int op;
        scanf("%d%d%d",&op,&a[i].x,&a[i].y);
        a[i].y=a[i].x-a[i].y;
        if(op==2)
            a[i].id=++k;
    }
    memset(ans,0x3f,sizeof(ans));
    bit::init();
    solve(1,n+m);
    for(int i=1;i<=k;i++)
        printf("%d\n",ans[i]);
    return 0;
}
posted @ 2026-10-15 08:24  ShanLiing  阅读(3)  评论(0)    收藏  举报
//雪花飘落效果