首页 > 代码库 > BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]

BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]

传送门

题意:

维护二维点集P,支持以下两个操作
(1)插入点(x,y)
(2)给定询问(x,y),求点集中离询问点最近的点
距离定义为曼哈顿距离
Dis(P1,P2)=|x1-x2|+|y1-y2|
n,m<=500000
x,y<=1000000


时间,$x$,$y$

$CDQ$分治里需要四个象限分类讨论,树状数组维护最大值

然后有两个象限是后缀和

然后跟$PoPoQQQ$学了一个神奇的技巧,树状数组加一个时间戳,就可以不用每次清空之前的操作了

 

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;typedef long long ll;const int N=1e6+5,M=1e6+5,INF=1e9;inline int read(){    char c=getchar();int x=0,f=1;    while(c<0||c>9){if(c==-)f=-1;c=getchar();}    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}    return x*f;}int cc[20];inline void put(int x){    if(x==0) putchar(0);    else{        int top=0;        while(x) cc[++top]=x%10,x/=10;        for(int i=top;i>=1;i--) putchar(0+cc[i]);    }    putchar(\n);}int n,m,qid,maxVal=-INF;struct Operation{    int x,y,op,id,qid;    Operation():op(0){}}a[N],t[N];int c[M],mark[M],cl;inline int lowbit(int x){return x&-x;}inline void upd(int p,int v){    for(;p<=maxVal;p+=lowbit(p)){        if(mark[p]!=cl) mark[p]=cl,c[p]=v;        else c[p]=max(c[p],v);    }}inline int que(int p){    int re=-INF;    for(;p;p-=lowbit(p))        if(mark[p]==cl) re=max(re,c[p]);    return re;}inline void upd2(int p,int v){    for(;p;p-=lowbit(p)){        if(mark[p]!=cl) mark[p]=cl,c[p]=v;        else c[p]=max(c[p],v);    }}inline int que2(int p){    int re=-INF;    for(;p<=maxVal;p+=lowbit(p))        if(mark[p]==cl) re=max(re,c[p]);    return re;}int ans[N];void sol(int l,int r){//printf("sol %d %d\n",l,r);    int mid=(l+r)>>1;    cl++;    for(int i=l;i<=r;i++){        if(!a[i].op&&a[i].id<=mid) upd(a[i].y,a[i].x+a[i].y);        else if(a[i].op&&a[i].id>mid) ans[a[i].qid]=min(ans[a[i].qid],a[i].x+a[i].y-que(a[i].y));    }    cl++;    for(int i=l;i<=r;i++){        if(!a[i].op&&a[i].id<=mid) upd2(a[i].y,a[i].x-a[i].y);        else if(a[i].op&&a[i].id>mid) ans[a[i].qid]=min(ans[a[i].qid],a[i].x-a[i].y-que2(a[i].y));    }    cl++;    for(int i=r;i>=l;i--){        if(!a[i].op&&a[i].id<=mid) upd(a[i].y,a[i].y-a[i].x);        else if(a[i].op&&a[i].id>mid) ans[a[i].qid]=min(ans[a[i].qid],a[i].y-a[i].x-que(a[i].y));    }    cl++;    for(int i=r;i>=l;i--){        if(!a[i].op&&a[i].id<=mid) upd2(a[i].y,-a[i].y-a[i].x);        else if(a[i].op&&a[i].id>mid) ans[a[i].qid]=min(ans[a[i].qid],-a[i].y-a[i].x-que2(a[i].y));    }    //for(int i=1;i<=qid;i++) printf("%d ",ans[i]);puts("end");}void CDQ(int l,int r){//printf("CDQ %d %d\n",l,r);    if(l==r) return;    int mid=(l+r)>>1;    CDQ(l,mid);CDQ(mid+1,r);    int i=l,j=mid+1,p=l;    while(i<=mid||j<=r){        if(j>r||(i<=mid&&a[i].x<=a[j].x)) t[p++]=a[i++];        else t[p++]=a[j++];    }    for(int i=l;i<=r;i++) a[i]=t[i];    sol(l,r);}int main(){    freopen("in","r",stdin);    //freopen("out","w",stdout);    n=read();m=read();    for(int i=1;i<=n;i++){        a[i].x=read()+1,a[i].y=read()+1,a[i].id=i;        maxVal=max(maxVal,max(a[i].x,a[i].y));    }    for(int i=1;i<=m;i++){        a[++n].op=read()-1,a[n].x=read()+1,a[n].y=read()+1,a[n].id=n;        if(a[n].op) a[n].qid=++qid;        maxVal=max(maxVal,max(a[n].x,a[n].y));    }    //for(int i=n-m+1;i<=n;i++) printf("check %d %d %d %d\n",i,a[i].x,a[i].y,a[i].qid);    //printf("n %d %d %d\n",n,qid,maxVal);    for(int i=1;i<=qid;i++) ans[i]=INF;    CDQ(1,n);    for(int i=1;i<=qid;i++) put(ans[i]);}

 

BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]