BZOJ2648: SJY擺棋子&&2716: [Violet 3]天使玩偶

BZOJ2648: SJY擺棋子php

BZOJ2716: [Violet 3]天使玩偶node

BZOJ氪金無極限。。。ios

其實這兩道是同一題。ui

附上2648的題面:spa

Description

這天,SJY顯得無聊。在家本身玩。
在一個棋盤上,有N個黑色棋子。
他每次要麼放到棋盤上一個黑色棋子,要麼放上一個白色棋子,若是是白色棋子,他會找出距離這個白色棋子最近的黑色棋子。
此處的距離是 曼哈頓距離 即(|x1-x2|+|y1-y2|) 。
如今給出N<=500000個初始棋子。和M<=500000個操做。
對於每一個白色棋子,輸出距離這個白色棋子最近的黑色棋子的距離。
同一個格子可能有多個棋子。

Input

第一行兩個數 N M
之後M行,每行3個數 t x y
若是t=1 那麼放下一個黑色棋子
若是t=2 那麼放下一個白色棋子

Output

對於每一個T=2 輸出一個最小距離

Sample Input

2 3
1 1
2 3
2 1 2
1 3 3
2 4 2

Sample Output

1
2

題解Here!

沒有插入操做,就無腦$K-D\ Tree$便可。
有了插入操做怎麼辦呢?
咱們能夠類比於平衡樹,查找要插入的點應該在什麼位置。
而後插入就好。
可是很容易就會發現這玩意會造成一條鏈。
複雜度筍乾爆炸。。。
怎麼辦呢?
$K-D\ Tree$一大缺點就是建好的樹不能再動。
暴力重建?
複雜度依然$GG$。。。
等一下!不能每次都暴力重建,那我就偶爾幾回暴力重建就是了?
對,這種方法已經被成功運用到替罪羊樹中。
設$\alpha=0.75$,當前在$x$處。
假如$x$的左右子樹中有一顆子樹的大小$>x\text{的子樹大小}\times\alpha$,說明該子樹已經極其不平衡。
咱們須要對其進行暴力拍平重建。
拍平代碼的話,大概長這個樣子:
void pia(int rt,int num){
    if(a[rt].lson)pia(a[rt].lson,num);
    point[num+a[a[rt].lson].size+1]=a[rt].point;
    recycle[++top]=rt;
    if(a[rt].rson)pia(a[rt].rson,num+a[a[rt].lson].size+1);
}
重建的話,和最開始的建樹過程相同。
這樣,插入操做就解決了。
指望複雜度$O(\text{能過})$。
附代碼:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define MAXN 1000010
#define MAX (1LL<<30)
#define Alpha 0.75
using namespace std;
int n,m,root,ans,size=0;
int top=0,recycle[MAXN];
bool sort_flag=false;
struct Point{
    int x,y;
    friend bool operator <(const Point &p,const Point &q){
        if(sort_flag)return p.y<q.y;
        return p.x<q.x;
    }
}point[MAXN],now;
struct Tree{
    Point point;
    int minx,miny,maxx,maxy,lson,rson,size;
}a[MAXN];
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline int get_dis(const Point &p,const Point &q){
    return abs(p.x-q.x)+abs(p.y-q.y);
}
inline int newnode(const Point &p){
    int rt;
    if(top)rt=recycle[top--];
    else rt=++size;
    a[rt].point=p;
    a[rt].maxx=a[rt].minx=p.x;
    a[rt].maxy=a[rt].miny=p.y;
    a[rt].lson=a[rt].rson=0;
    a[rt].size=1;
    return rt;
}
inline void pushup(int rt){
    int lson=a[rt].lson,rson=a[rt].rson;
    a[rt].size=a[lson].size+a[rson].size+1;
    a[rt].maxx=max(a[rt].maxx,max(a[lson].maxx,a[rson].maxx));
    a[rt].maxy=max(a[rt].maxy,max(a[lson].maxy,a[rson].maxy));
    a[rt].minx=min(a[rt].minx,min(a[lson].minx,a[rson].minx));
    a[rt].miny=min(a[rt].miny,min(a[lson].miny,a[rson].miny));
}
void buildtree(int l,int r,int &rt,int flag){
    int mid=l+r>>1;
    sort_flag=flag;
    nth_element(point+l,point+mid,point+r+1);
    rt=newnode(point[mid]);
    if(l<mid)buildtree(l,mid-1,a[rt].lson,flag^1);
    if(mid<r)buildtree(mid+1,r,a[rt].rson,flag^1);
    pushup(rt);
}
void pia(int rt,int num){
    if(a[rt].lson)pia(a[rt].lson,num);
    point[num+a[a[rt].lson].size+1]=a[rt].point;
    recycle[++top]=rt;
    if(a[rt].rson)pia(a[rt].rson,num+a[a[rt].lson].size+1);
}
void check(int &rt,int flag){
    if(Alpha*a[rt].size<max(a[a[rt].lson].size,a[a[rt].rson].size)){
        pia(rt,0);
        buildtree(1,a[rt].size,rt,flag);
    }
}
void insert(int &rt,int flag){
    if(!rt){
        rt=newnode(now);
        return;
    }
    sort_flag=flag;
    if(a[rt].point<now)insert(a[rt].rson,flag^1);
    else insert(a[rt].lson,flag^1);
    pushup(rt);
    check(rt,flag);
}
inline int max_dis(int rt){
    int x,y;
    x=max(now.x-a[rt].maxx,0)+max(a[rt].minx-now.x,0);
    y=max(now.y-a[rt].maxy,0)+max(a[rt].miny-now.y,0);
    return x+y;
}
void query(int rt){
    int dis=get_dis(a[rt].point,now),ldis=MAX,rdis=MAX;
    ans=min(ans,dis);
    if(a[rt].lson)ldis=max_dis(a[rt].lson);
    if(a[rt].rson)rdis=max_dis(a[rt].rson);
    if(ldis<rdis){
        if(ldis<ans)query(a[rt].lson);
        if(rdis<ans)query(a[rt].rson);
    }
    else{
        if(rdis<ans)query(a[rt].rson);
        if(ldis<ans)query(a[rt].lson);
    }
}
void work(){
    int f;
    while(m--){
        f=read();now.x=read();now.y=read();
        if(f==1)insert(root,0);
        else{
            ans=MAX;
            query(root);
            printf("%d\n",ans);
        }
    }
}
void init(){
    n=read();m=read();
    a[0].maxx=a[0].maxy=-MAX;
    a[0].minx=a[0].miny=MAX;
    for(int i=1;i<=n;i++){point[i].x=read();point[i].y=read();}
    buildtree(1,n,root,0);
}
int main(){
    init();
    work();
    return 0;
}
相關文章
相關標籤/搜索