BZOJ2648/2716:SJY摆棋子/[Violet]天使玩偶(K-D Tree)

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

Solution

K-D Tree模板题,注意不替罪羊重构的话会TLE

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<algorithm>
  6 #define N (1000000+1000)
  7 #define INF 0x7fffffff
  8 using namespace std;
  9 
 10 int n,m,D,ans,opt,x,y,Root;
 11 double alpha=0.75;
 12 
 13 struct Node
 14 {
 15     int d[2],Max[2],Min[2],lson,rson,size;
 16     bool operator < (const Node &a) const {return d[D]<a.d[D];}
 17     Node (int x=0,int y=0)
 18     {
 19         lson=rson=0; d[0]=x; d[1]=y;;
 20         Max[0]=Min[0]=d[0];
 21         Max[1]=Min[1]=d[1];
 22     }
 23 }p[N],T;
 24 
 25 int stack[N],cnt,top;
 26 int NewNode()
 27 {
 28     if (top) return stack[top--];
 29     return ++cnt;
 30 }
 31 
 32 struct KDT
 33 {
 34     Node Tree[N];
 35     
 36     void Update(int now)
 37     {
 38         int ls=Tree[now].lson,rs=Tree[now].rson;
 39         for (int i=0; i<=1; ++i)
 40         {
 41             Tree[now].Max[i]=Tree[now].Min[i]=Tree[now].d[i];
 42             if (ls)
 43             {
 44                 Tree[now].Max[i]=max(Tree[now].Max[i],Tree[ls].Max[i]);
 45                 Tree[now].Min[i]=min(Tree[now].Min[i],Tree[ls].Min[i]);
 46             }
 47             if (rs)
 48             {
 49                 Tree[now].Max[i]=max(Tree[now].Max[i],Tree[rs].Max[i]);
 50                 Tree[now].Min[i]=min(Tree[now].Min[i],Tree[rs].Min[i]);
 51             }
 52         }
 53         Tree[now].size=Tree[ls].size+Tree[rs].size+1;
 54     }
 55     int Build(int opt,int l,int r)
 56     {
 57         if (l>r) return 0;
 58         int mid=(l+r)>>1,now=NewNode();
 59         D=opt; nth_element(p+l,p+mid,p+r+1);
 60         Tree[now]=p[mid]; Tree[now].size=1;
 61         Tree[now].lson=Build(opt^1,l,mid-1);
 62         Tree[now].rson=Build(opt^1,mid+1,r);
 63         Update(now);
 64         return now;
 65     }
 66     int Get_min(int now)
 67     {
 68         int ans=0;
 69         for (int i=0; i<=1; ++i)
 70         {
 71             ans+=max(0,T.d[i]-Tree[now].Max[i]);
 72             ans+=max(0,Tree[now].Min[i]-T.d[i]);
 73         }
 74         return ans;
 75     }
 76     void Query(int now)
 77     {
 78         ans=min(ans,abs(T.d[0]-Tree[now].d[0])+abs(T.d[1]-Tree[now].d[1]));
 79         int ls=Tree[now].lson,rs=Tree[now].rson,lans=INF,rans=INF;
 80         if (ls) lans=Get_min(ls);
 81         if (rs) rans=Get_min(rs);
 82         if (lans<rans)
 83         {
 84             if (lans<ans) Query(ls);
 85             if (rans<ans) Query(rs);
 86         }
 87         else
 88         {
 89             if (rans<ans) Query(rs);
 90             if (lans<ans) Query(ls);
 91         }
 92     }
 93     void Dfs(int now,int sz)
 94     {
 95         int ls=Tree[now].lson,rs=Tree[now].rson;
 96         if (ls) Dfs(ls,sz);
 97         p[sz+Tree[ls].size]=Tree[now];
 98         stack[++top]=now;
 99         if (rs) Dfs(rs,sz+Tree[ls].size+1);
100     }
101     void Check(int &now,int opt)
102     {
103         int ls=Tree[now].lson, rs=Tree[now].rson;
104         if (Tree[ls].size>alpha*Tree[now].size || Tree[rs].size>alpha*Tree[now].size)
105         {
106             Dfs(now,1);
107             now=Build(opt,1,Tree[now].size);
108         }
109     }
110     void Insert(int &now,int x,int opt)
111     {
112         if (Tree[x].d[opt]<=Tree[now].d[opt])
113         {
114             if (Tree[now].lson) Insert(Tree[now].lson,x,opt^1);
115             else Tree[now].lson=x;
116         }
117         else
118         {
119             if (Tree[now].rson) Insert(Tree[now].rson,x,opt^1);
120             else Tree[now].rson=x;
121         }
122         Update(now); Check(now,opt);
123     }
124 }KDT;
125 
126 int main()
127 {
128     scanf("%d%d",&n,&m);
129     for (int i=1; i<=n; ++i)
130     {
131         scanf("%d%d",&x,&y);
132         p[i].d[0]=x; p[i].d[1]=y;
133     }
134     Root=KDT.Build(0,1,n);
135     for (int i=1; i<=m; ++i)
136     {
137         scanf("%d%d%d",&opt,&x,&y);
138         if (opt==1)
139         {
140             int t=NewNode();
141             KDT.Tree[t]=Node(x,y);
142             KDT.Tree[t].size=1;
143             KDT.Insert(Root,t,0);
144         }
145         else
146         {
147             T.d[0]=x; T.d[1]=y; ans=INF;
148             KDT.Query(Root);
149             printf("%d\n",ans);
150         }
151     }
152 }

转载于:https://www.cnblogs.com/refun/p/9301608.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值