BZOJ2716天使玩偶

不会KD-tree怎么办?CQD硬搞。

建立正常的平面直角坐标系,首先我们只考虑在目标点左下角的点对目标点的贡献,由于左下点的横纵坐标都小于目标点,那么曼哈顿距离就可以化简了,绝对值去掉后,得到$x2+y2-(x1+y1)$,那么我们的目标就转化为了求横纵坐标以及时间轴都小于目标查询点的更改点所作出的贡献,这是一个三维偏序问题,我们在树状数组中维护x+y的最大值,进而即可更新答案。

可是这样做我们只是考虑了左下角点的贡献,肯定是会出错的,但是其余位置的点不容易化简绝对值,或者化简完以后的形式比较难以维护,而且个人认为分类的话码量略大。

那么我们换一个角度,如何将其余位置的点都变化到目标点的左下角。

直接翻转坐标系就行了,把所有点的横纵坐标都翻转一下,使之分别落于其他象限。那么再次调用cdq即可,注意防负下标。

这样打的好处就是比较无脑,而且正确性保障很大,但是常数这种东西还是很神奇的。(本代码不保证Bzoj可A)(其实应该不可A,因为main函数返回值是signed)

#include
#define lowbit(x) (x&(-x))
#define int long long 
using namespace std;
const int inf=0x7fffffffffffff;
int read(){
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){
        if(x=='-') f=-1;
        x=getchar();
    }while(x>='0'&&x<='9'){
        sum=sum*10+x-'0';
        x=getchar();
    }return sum*f;
}
struct rec{
    int x,y,t,id,ty;
    friend bool operator < (const rec &a,const rec &b){
        if(a.t==b.t){
            if(a.x==b.x) return a.y<b.y;
            else return a.x<b.x;
        }else return a.t<b.t;
    }
}q[6005000],tmp[6005000];
int n,m,kind,Max,ans[3005000],tr[10005000],_time=1,mk[10005000];
void change(int pos,int val){
    if(!pos) return ;
    for(int i=pos;i<=Max;i+=lowbit(i))
        if(mk[i]!=_time){
            mk[i]=_time;
            tr[i]=val;
        }
        else tr[i]=max(tr[i],val);
}
int ask(int pos){
    int ans=-inf;
    for(int i=pos;i;i-=lowbit(i))
        if(mk[i]==_time) ans=max(ans,tr[i]);
    return ans;
}
void cdq(int l,int r){
    if(l==r) return ;
    int mid=l+r>>1;
    cdq(l,mid);cdq(mid+1,r);
    int i=l,j=mid+1,tot=l;
    while(i<=mid&&j<=r){
        if(q[i].x<=q[j].x){
            tmp[tot]=q[i];
            if(!q[i].ty)
                change(q[i].y,q[i].x+q[i].y);
            ++tot;++i;
        }else {
            tmp[tot]=q[j];
            if(q[j].ty)
                ans[q[j].id]=min(ans[q[j].id],q[j].x+q[j].y-ask(q[j].y));
            ++tot;++j;
        }
    }
    while(i<=mid){
        tmp[tot]=q[i];
//        if(!q[i].ty)
//            change(q[i].y,q[i].x+q[i].y);
        ++tot;++i;
    }
    while(j<=r){
        tmp[tot]=q[j];
        if(q[j].ty)
            ans[q[j].id]=min(ans[q[j].id],q[j].x+q[j].y-ask(q[j].y));
        ++tot;++j;
    }
/*    for(int i=1;i<=Max;i++)
        cout<*/
//    for(int k=l;k<=mid;k++) 
    //    if(!q[i].ty) del(q[k].y);
/*    for(int i=1;i<=Max;i++)
        cout<*/
    _time++;
//    if(_time>=10000000000) _time=1;
    for(int k=l;k<=r;k++) q[k]=tmp[k];
}
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        q[i].x=read()+1;q[i].y=read()+1;
        q[i].t=0;q[i].ty=0;
        Max=max(Max,max(q[i].x,q[i].y));
    }
    for(int i=1;i<=m;i++){
        kind=read();
        if(kind&1){
            q[i+n].x=read()+1;q[i+n].y=read()+1;
            q[i+n].t=i;q[i].ty=0;
        }else {
            q[i+n].x=read()+1;q[i+n].y=read()+1;
            q[i+n].t=i;q[i+n].ty=1;
            q[i+n].id=++ans[0];
            ans[ans[0]]=inf;
        }
        Max=max(Max,max(q[i+n].x,q[i+n].y));
    }n+=m;
//    cout<<"Max="<
    sort(q+1,q+n+1);
    cdq(1,n);
/*    for(int i=1;i<=n;i++)
        cout<*/
    for(int i=1;i<=n;i++) q[i].x=-q[i].x+Max+1;
    sort(q+1,q+1+n);
/*    for(int i=1;i<=n;i++)
        cout<*/
    cdq(1,n);
    for(int i=1;i<=n;i++) q[i].y=-q[i].y+Max+1;
    sort(q+1,q+1+n);
    cdq(1,n);
    for(int i=1;i<=n;i++) q[i].x=-q[i].x+Max+1;
    sort(q+1,q+n+1);
    cdq(1,n);
    for(int i=1;i<=ans[0];i++)
        printf("%lld\n",ans[i]);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Yu-shi/p/11252540.html

你可能感兴趣的:(BZOJ2716天使玩偶)