bzoj 2648 SJY摆棋子

题目大意:

在一个棋盘上,有N个黑色棋子

每次放到棋盘上一个黑色或白色棋子,如果是白色棋子,他会找出距离(曼哈顿)这个白色棋子最近的黑色棋子

对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离

同一个格子可能有多个棋子

思路:

直接kd tree裸题

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<vector>
  9 #include<map>
 10 #define ll long long
 11 #define inf 2139062143
 12 #define MAXN 500100
 13 using namespace std;
 14 inline int read()
 15 {
 16     int x=0,f=1;char ch=getchar();
 17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
 18     while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
 19     return x*f;
 20 }
 21 int n,m,rt,dim,ans;
 22 struct node
 23 {
 24     int d[2],mn[2],mx[2],l,r;
 25     node() {d[1]=d[0]=l=r=0;}
 26 }tr[MAXN<<1],g;
 27 bool operator < (node a,node b) {return a.d[dim]<b.d[dim];}
 28 int dis(node a,node b) {return abs(a.d[0]-b.d[0])+abs(a.d[1]-b.d[1]);}
 29 struct kd_tree
 30 {
 31     void upd(int k)
 32     {
 33         node l=tr[tr[k].l],r=tr[tr[k].r];
 34         for(int i=0;i<2;i++)
 35         {
 36             if(tr[k].l) tr[k].mn[i]=min(tr[k].mn[i],l.mn[i]),tr[k].mx[i]=max(tr[k].mx[i],l.mx[i]);
 37             if(tr[k].r) tr[k].mn[i]=min(tr[k].mn[i],r.mn[i]),tr[k].mx[i]=max(tr[k].mx[i],r.mx[i]);
 38         }
 39     }
 40     int build(int l,int r,int now)
 41     {
 42         dim=now;
 43         int mid=(l+r)>>1;
 44         nth_element(tr+l,tr+mid,tr+r+1);
 45         for(int i=0;i<2;i++) tr[mid].mn[i]=tr[mid].mx[i]=tr[mid].d[i];
 46         if(l<mid) tr[mid].l=build(l,mid-1,now^1);
 47         if(r>mid) tr[mid].r=build(mid+1,r,now^1);
 48         upd(mid);
 49         return mid;
 50     }
 51     int get(int k,node p)
 52     {
 53         int res=0;
 54         for(int i=0;i<2;i++) res+=max(0,tr[k].mn[i]-p.d[i]);
 55         for(int i=0;i<2;i++) res+=max(0,p.d[i]-tr[k].mx[i]);
 56         return res;
 57     }
 58     void insert(int k,int now)
 59     {
 60         if(g.d[now]>=tr[k].d[now])
 61         {
 62             if(tr[k].r)insert(tr[k].r,now^1);
 63             else 
 64             {
 65                 tr[k].r=++n,tr[n]=g;
 66                 for(int i=0;i<2;i++) tr[n].mn[i]=tr[n].mx[i]=tr[n].d[i];
 67             }
 68         }
 69         else 
 70         {
 71             if(tr[k].l) insert(tr[k].l,now^1);
 72             else 
 73             {
 74                 tr[k].l=++n,tr[n]=g;
 75                 for(int i=0;i<2;i++) tr[n].mn[i]=tr[n].mx[i]=tr[n].d[i];
 76             }
 77         }
 78         upd(k);
 79     }
 80     void query(int k,int now)
 81     {
 82         int d,dl=inf,dr=inf;
 83         d=dis(tr[k],g);
 84         ans=min(ans,d);
 85         if(tr[k].l) dl=get(tr[k].l,g);
 86         if(tr[k].r) dr=get(tr[k].r,g);
 87         if(dl<dr)
 88         {
 89             if(dl<ans) query(tr[k].l,now^1);
 90             if(dr<ans) query(tr[k].r,now^1);
 91         }
 92         else
 93         {
 94             if(dr<ans) query(tr[k].r,now^1);
 95             if(dl<ans) query(tr[k].l,now^1);
 96         }
 97     }
 98 }kd;
 99 int main()
100 {
101     n=read();m=read();
102     int x,y,z;
103     for(int i=1;i<=n;i++) tr[i].d[0]=read(),tr[i].d[1]=read();
104     rt=kd.build(1,n,0);
105     while(m--)
106     {
107         z=read(),x=read(),y=read();
108         if(z==1) {g.d[0]=x,g.d[1]=y,g.l=g.r=0;kd.insert(rt,0);}
109         else {ans=inf,g.d[0]=x,g.d[1]=y,g.l=g.r=0;kd.query(rt,0);printf("%d\n",ans);}
110     }
111 }
View Code

今天学会了kd tree 就是一个本质为BST来实现线段树的树

 

posted @ 2018-02-06 10:56  jack_yyc  阅读(181)  评论(0编辑  收藏  举报