隐藏
「bzoj3815」卡常数 - K-D树+精准距离查询 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「bzoj3815」卡常数 - K-D树+精准距离查询

题目大意

    三维空间里有$n$个点,每次修改一个点的坐标,或者查询距离$(x,y,z)$为$r$的点(保证有且只有一个解)
    加密方式:设函数$f(x)=ax−b\sin(x)$,对于所有事件中的参数$(i,x,y,z,r)$,均加密成$f(last_res\times\text{原值}+1)$,其中$last_res$为上一个实验事件的返回值(即发现的摄像头编号),若之前未进行过实验则$last_res=0.1$。
    $0 \leq b < a < 5$,坐标的绝对值均不超过$100$,所有坐标均为随机生成且至少精确到$10^{−5}$。


题目分析

问题很简单,套个K-D树就可以了。
难点在于解密。

发现$0 \leq b < a < 5$,故函数单调,二分即可。
如果没这个偏序关系的话,就要牛顿迭代了。

注意题目的提示在坑爹,不能用long double,否则你就会“卡常数”。
注意二分和K-D树不能用一套eps


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include<bits/stdc++.h>

using namespace std;

inline int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(!isdigit(x)) {if(x=='-')bj=-1;x=getchar();}
while(isdigit(x)) {num=num*10+x-'0';x=getchar();}
return num*bj;
}

const int maxn=131075,K=3;
const double eps=1e-6;

int dcmp(double x) {return fabs(x)<=eps?0:(x>eps?1:-1);}
double sqr(double x) {return x*x;}

int D;

struct Point {
double d[K],Min[K],Max[K];
int id;
int ls,rs;
bool del;
double& operator [] (int x) {return d[x];}
bool operator < (const Point &b) const {return d[D]<b.d[D];}
bool operator == (const Point &b) const {
for(int i=0; i<K; i++)if(dcmp(d[i]-b.d[i]))return 0;
return 1;
}
} p[maxn];

int pos[maxn];
double ans=0.1;
bool bj=1;

struct KD_Tree {
#define lson p[index].ls
#define rson p[index].rs
void push_up(int index) {
for(int i=0; i<K; i++) {
if(!p[index].del)p[index].Min[i]=p[index].Max[i]=p[index][i];
else p[index].Min[i]=1e18;
if(lson) {
p[index].Min[i]=min(p[index].Min[i],p[lson].Min[i]);
p[index].Max[i]=max(p[index].Max[i],p[lson].Max[i]);
}
if(rson) {
p[index].Min[i]=min(p[index].Min[i],p[rson].Min[i]);
p[index].Max[i]=max(p[index].Max[i],p[rson].Max[i]);
}
}
}
int build(int Left,int Right,int now) {
int mid=(Left+Right)>>1,root=mid;
D=now;
nth_element(p+Left,p+mid,p+Right+1);
pos[p[mid].id]=root;
if(Left<mid)p[root].ls=build(Left,mid-1,(now+1)%K);
if(Right>mid)p[root].rs=build(mid+1,Right,(now+1)%K);
push_up(root);
return root;
}
int insert(int index,int id,int now) {
if(!index) {push_up(id);return id;}
if(p[id][now]<=p[index][now])lson=insert(lson,id,(now+1)%K);
else rson=insert(rson,id,(now+1)%K);
push_up(index);
return index;
}
double get_max(int index,Point P) {
if(!index)return 0;
double ans=0;
for(int i=0; i<K; i++)ans+=max(sqr(p[index].Max[i]-P[i]),sqr(p[index].Min[i]-P[i]));
return ans;
}
double get_min(int index,Point P) {
if(!index)return 1e18;
double ans=0;
for(int i=0; i<K; i++) {
if(p[index].Min[i]-P[i]>0)ans+=sqr(p[index].Min[i]-P[i]);
if(P[i]-p[index].Max[i]>0)ans+=sqr(P[i]-p[index].Max[i]);
}
return ans;
}
double dist(Point a,Point b) {
double ans=0;
for(int i=0; i<K; i++)ans+=sqr(a[i]-b[i]);
return ans;
}
void find(int index,Point P,double r) {
if(!index||bj||dcmp(get_min(index,P)-r)>0||dcmp(get_max(index,P)-r)<0)return;
double Dist=dist(p[index],P);
if(!p[index].del&&dcmp(Dist-r)==0) {ans=p[index].id;bj=1;return;}
find(lson,P,r);
find(rson,P,r);
}
void erase(int index,Point P,int now) {
if(p[index]==P) {p[index].del=1;push_up(index);return;}
if(P[now]<=p[index][now])erase(lson,P,(now+1)%K);
else erase(rson,P,(now+1)%K);
push_up(index);
}
} tree;

int n,m;
double a,b,x,y,i;

double decode(double v,double Left=-100,double Right=100) {
while(Right-Left>1e-9) {
double mid=(Left+Right)/2,x=mid*ans+1;
if(v>x*a-b*sin(x))Left=mid;
else Right=mid;
}
return (Left+Right)/2;
}

int main() {
n=Get_Int();
m=Get_Int();
scanf("%lf%lf",&a,&b);
for(int i=1; i<=n; i++) {
for(int j=0; j<K; j++)scanf("%lf",&p[i].d[j]);
p[i].id=i;
}
int root=tree.build(1,n,0);
while(m--) {
int opt=Get_Int();
if(opt==0) {
scanf("%lf",&i);
int x=round(decode(i,1,n));
n++;
for(int j=0; j<K; j++) {
scanf("%lf",&y);
p[n][j]=decode(y);
}
tree.erase(root,p[pos[x]],0);
p[pos[x]=n].id=x;
tree.insert(root,n,0);
} else {
Point P;
for(int i=0; i<K; i++) {
scanf("%lf",&y);
P[i]=decode(y);
}
double r;
scanf("%lf",&r);
r=sqr(decode(r,0,350));
bj=0;
tree.find(root,P,r);
printf("%d\n",(int)ans);
}
}
return 0;
}
姥爷们赏瓶冰阔落吧~