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]);
}

 

posted @ 2017-02-25 10:41  Candy?  阅读(451)  评论(0编辑  收藏  举报