2648: SJY摆棋子
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2739 Solved: 939
[ Submit][ Status][ Discuss]
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
1 1
2 3
2 1 2
1 3 3
2 4 2
Sample Output
1
2
HINT
kdtree可以过
Source
HINT既然说了kdtree那就kdtree吧。。
建树的话,,上篇blog转载了一位大牛的做法,这里就不说了
不过苟蒻之前对kdtree的功能还不是很熟
插入操作:
kdtree建好后每次沿着当前比较关键字(x坐标或y坐标)往下走,走到空位就插进去
查询操作:
对于每个位置维护当前坐标的极大/小值,如果某一维需要查询的坐标在这之间,这一维贡献为0,否则就可以计算出贡献,用这种方法预估dis
对于nth_element函数:
nth_element(a+l,a+mid,a+r)能在O(n)时间内对区间[l,r)内的元素进行一次粗略排序,使得第mid个元素恰好在mid位置上
此题还有数据加强板2716,双倍经验~
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 1E6 + 3E5 + 10;
const int INF = ~0U>>1;
struct Point{
int x,y;
Point(){}
Point(int x,int y): x(x),y(y){}
}p[maxn];
int n,m,cnt,ans,td[2],D[maxn][2],ma[maxn][2],mi[maxn][2],ch[maxn][2];
void maintain(int x)
{
for (int i = 0; i < 2; i++)
if (ch[x][i])
for (int j = 0; j < 2; j++) {
ma[x][j] = max(ma[x][j],ma[ch[x][i]][j]);
mi[x][j] = min(mi[x][j],mi[ch[x][i]][j]);
}
}
bool cmp0(const Point &a,const Point &b) {return a.x < b.x;}
bool cmp1(const Point &a,const Point &b) {return a.y < b.y;}
int Build(int l,int r,int k)
{
int mid = (l + r) >> 1;
if (!k) nth_element(p + l,p + mid,p + r + 1,cmp0);
else nth_element(p + l,p + mid,p + r + 1,cmp1);
int ret = ++cnt;
D[cnt][0] = ma[cnt][0] = mi[cnt][0] = p[mid].x;
D[cnt][1] = ma[cnt][1] = mi[cnt][1] = p[mid].y;
if (l < mid) ch[ret][0] = Build(l,mid-1,k^1);
if (mid < r) ch[ret][1] = Build(mid+1,r,k^1);
maintain(ret);
return ret;
}
void Insert(int &x,int k)
{
if (!x) {
x = ++cnt;
for (int i = 0; i < 2; i++)
D[x][i] = ma[x][i] = mi[x][i] = td[i];
return;
}
if (D[x][0] == td[0] && D[x][1] == td[1]) return;
int d = td[k] <= D[x][k]?0:1;
Insert(ch[x][d],k^1);
maintain(x);
}
int dis(int x)
{
if (!x) return INF;
int ret = 0;
if (td[0] < mi[x][0]) ret += mi[x][0] - td[0];
if (ma[x][0] < td[0]) ret += td[0] - ma[x][0];
if (td[1] < mi[x][1]) ret += mi[x][1] - td[1];
if (ma[x][1] < td[1]) ret += td[1] - ma[x][1];
return ret;
}
void Query(int x)
{
int now = abs(td[0] - D[x][0]) + abs(td[1] - D[x][1]);
ans = min(ans,now);
int A = dis(ch[x][0]);
int B = dis(ch[x][1]);
if (A < B) {
if (ch[x][0] && A < ans) Query(ch[x][0]);
if (ch[x][1] && B < ans) Query(ch[x][1]);
}
else {
if (ch[x][1] && B < ans) Query(ch[x][1]);
if (ch[x][0] && A < ans) Query(ch[x][0]);
}
}
int getint()
{
char ch = getchar();
int ret = 0,a = 1;
while (ch < '0' || '9' < ch) {
if (ch == '-') a = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret*a;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint();
m = getint();
for (int i = 1; i <= n; i++) {
int x = getint();
int y = getint();
p[i] = Point(x,y);
}
int Root = Build(1,n,0);
while (m--) {
int t = getint();
td[0] = getint();
td[1] = getint();
if (t == 1) Insert(Root,0);
else {
ans = INF;
Query(Root);
printf("%d\n",ans);
}
}
return 0;
}