[BZOJ2716][Violet 3]天使玩偶(cdq分治||KD-tree)

题目:

我是超链接

题解:

这题目一眼KD-tree啊,写了一发A了,等等我不是要练cdq分治吗
然后又写了cdq分治,其实不管对于这两个的哪个都是模板题啦

KD-tree:真·模板题
cdq分治:
首先考虑如果只要求一个点左下角与它最近的点有多远
设给定的点为(x,y),左下角有某个点(u,v)
就是要求(x-u)+(y-v)最小。
也就是要求(x+y)-(u+v)最小。
现在整理一下条件:
1.出现时间在它前面
2.x坐标小于它
3.y坐标小于它
维护一个可以查询前缀最大值的树状数组
按时间排序,按x分治
以y为关键字将(x+y)加入树状数组
通过坐标变换,做4遍就可以得到答案
把初始的那些点看成是在0时刻加入的点
这种把初始存在的东西看成操作的思路也很常见
但是KD-tree的要快,是不是我cdq分治写的太丑了?

代码:

KD-tree

#include <cstdio>
#include <iostream>
#include <algorithm>
#define INF 1e9
using namespace std;
const int N=1000005;
struct hh{int mn[2],mx[2],d[2],l,r,id;}t[N];
int cmpd,x,y,n,root,ans,m;
int cmp(const hh &a,const hh &b){return ( (a.d[cmpd]<a.d[cmpd]) || (a.d[cmpd]==a.d[cmpd] && a.d[!cmpd]<b.d[!cmpd]));}
void updata(int now)
{
    int lc=t[now].l,rc=t[now].r;
    if (lc)
    {
        t[now].mn[0]=min(t[now].mn[0],t[lc].mn[0]);
        t[now].mn[1]=min(t[now].mn[1],t[lc].mn[1]);
        t[now].mx[0]=max(t[now].mx[0],t[lc].mx[0]);
        t[now].mx[1]=max(t[now].mx[1],t[lc].mx[1]);
    }
    if (rc)
    {
        t[now].mn[0]=min(t[now].mn[0],t[rc].mn[0]);
        t[now].mn[1]=min(t[now].mn[1],t[rc].mn[1]);
        t[now].mx[0]=max(t[now].mx[0],t[rc].mx[0]);
        t[now].mx[1]=max(t[now].mx[1],t[rc].mx[1]);
    }
}
int build(int l,int r,int d)
{
    cmpd=d;
    int mid=(l+r)>>1;
    nth_element(t+l+1,t+mid+1,t+r+1,cmp);
    t[mid].mn[0]=t[mid].mx[0]=t[mid].d[0];
    t[mid].mn[1]=t[mid].mx[1]=t[mid].d[1];
    if (l!=mid) t[mid].l=build(l,mid-1,!d);
    if (r!=mid) t[mid].r=build(mid+1,r,!d);
    updata(mid); return mid;
}
void insert(int neww)
{
    int D,now;
    D=0; now=root;
    while (1)
    {
        t[now].mn[0]=min(t[now].mn[0],t[neww].mn[0]);
        t[now].mn[1]=min(t[now].mn[1],t[neww].mn[1]);
        t[now].mx[0]=max(t[now].mx[0],t[neww].mx[0]);
        t[now].mx[1]=max(t[now].mx[1],t[neww].mx[1]);
        if (t[neww].d[D]>=t[now].d[D])
        {
            if (!t[now].r) {t[now].r=neww;break;}
            else now=t[now].r;
        }else
        {
            if (!t[now].l) {t[now].l=neww;break;}
            else now=t[now].l;
        }
        D=!D;
    }
}
int dis(int now)
{
    int ans=0;
    if (x<t[now].mn[0]) ans+=t[now].mn[0]-x;
    if (x>t[now].mx[0]) ans+=x-t[now].mx[0];
    if (y<t[now].mn[1]) ans+=t[now].mn[1]-y;
    if (y>t[now].mx[1]) ans+=y-t[now].mx[1];
    return ans;
}
void ask(int now)
{
    int d0,dl,dr;
    d0=abs(t[now].d[0]-x)+abs(t[now].d[1]-y);
    if (d0<ans) ans=d0;
    if (t[now].l) dl=dis(t[now].l);else dl=INF;
    if (t[now].r) dr=dis(t[now].r);else dr=INF;
    if (dl<dr)
    {
        if (dl<ans) ask(t[now].l);
        if (dr<ans) ask(t[now].r);
    }else 
    {
        if (dr<ans) ask(t[now].r);
        if (dl<ans) ask(t[now].l);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d%d",&t[i].d[0],&t[i].d[1]);
    root=build(1,n,0);
    for (int i=1;i<=m;i++)
    {
        int id;
        scanf("%d%d%d",&id,&x,&y);
        if (id==1)
        {
            ++n;
            t[n].mn[0]=t[n].mx[0]=t[n].d[0]=x; 
            t[n].mn[1]=t[n].mx[1]=t[n].d[1]=y;
            insert(n);
        }else 
        {
            ans=INF;ask(root);printf("%d\n",ans);
        }
    }
}

CDQ分治

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 1e9
using namespace std;
const int N=1000005;
struct hh{int x,y,id;}f[N],jl[N],e[N];
int c[N],ans[N],inf;bool flag[N];
void add(int loc,int val)
{
    for (int i=loc;i<=inf;i+=i&(-i))
      c[i]=max(c[i],val);
}
int qurry(int loc)
{
    int ans=0;
    for (int i=loc;i>=1;i-=i&(-i)) ans=max(c[i],ans);
    return ans==0?-INF:ans;
}
void clear(int loc)
{
    for (int i=loc;i<=inf;i+=i&(-i)) c[i]=0;
}
void cdq(int l,int r)
{
    if (l>=r) return;
    int mid=(l+r)>>1;
    cdq(l,mid); cdq(mid+1,r);
    int t1=l,t2=mid+1;
    for (int i=l;i<=r;i++)
    {
        if ((t1<=mid && f[t1].x<=f[t2].x)||t2>r)
        {
            jl[i]=f[t1];
            if (!flag[f[t1].id]) add(f[t1].y,f[t1].x+f[t1].y);
            t1++;
        }else
        {
            jl[i]=f[t2];
            ans[f[t2].id]=min(ans[f[t2].id],f[t2].x+f[t2].y-qurry(f[t2].y));
            t2++;
        }
    }
    for (int i=l;i<=mid;i++) if (!flag[f[i].id]) clear(f[i].y);
    for (int i=l;i<=r;i++) f[i]=jl[i];
}
int cmp(hh a,hh b){return a.id<b.id;}
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) 
    {
        scanf("%d%d",&e[i].x,&e[i].y);
        e[i].id=i;
        inf=max(inf,e[i].x); inf=max(inf,e[i].y);
    }
    m+=n;
    for (int i=n+1;i<=m;i++)
    {
        int id;scanf("%d",&id);
        if (id==2) flag[i]=1;
        scanf("%d%d",&e[i].x,&e[i].y);
        e[i].id=i;
        inf=max(inf,e[i].x); inf=max(inf,e[i].y);
    }
    memset(ans,0x7f,sizeof(ans));
    for (int i=1;i<=m;i++) f[i]=e[i]; cdq(1,m);
    for (int i=1;i<=m;i++) f[i]=e[i],f[i].y=inf-f[i].y+1; cdq(1,m);
    for (int i=1;i<=m;i++) f[i]=e[i],f[i].x=inf-f[i].x+1;  cdq(1,m);
    for (int i=1;i<=m;i++) f[i]=e[i],f[i].x=inf-f[i].x+1,f[i].y=inf-f[i].y+1; cdq(1,m);
    for (int i=n+1;i<=m;i++) if (flag[i]) printf("%d\n",ans[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值