Kd-tree
基操
解决K维的一般数据结构能解决的问题:
- 求点距离(各种意义下的),其中如果是\(|x_i-x_j|+|y_i-y_j|\)可以化掉绝对值用树状数组维护
- 修改+查询(直接dfs,把所有能想到的剪枝都加上去)
模板
相当于维护了一棵平衡树?
Luogu P4169 [Violet]天使玩偶/SJY摆棋子
#include<bits/stdc++.h>
const int INF=1e9;
using namespace std;
inline int rd() {
int ret=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-'0';
return ret;
}
const int N=1e6+5;
int n,m,ls[N],rs[N],sz[N],c[N],qx,qy,ans,rt;
struct A{
int x,y,l[2],r[2],w;
}a[N];
inline bool cmpx(int i,int j) {
return a[i].x<a[j].x;
}
inline bool cmpy(int i,int j) {
return a[i].y<a[j].y;
}
inline void up(int p) {
sz[p]=sz[ls[p]]+sz[rs[p]]+1;
a[p].l[0]=a[p].r[0]=a[p].x;
a[p].l[1]=a[p].r[1]=a[p].y;
if(ls[p]) {
a[p].l[0]=min(a[p].l[0],a[ls[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[ls[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[ls[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[ls[p]].r[1]);
}
if(rs[p]) {
a[p].l[0]=min(a[p].l[0],a[rs[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[rs[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[rs[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[rs[p]].r[1]);
}
}
inline void bld(int &p,int l,int r) {
if(l>r) {
p=0; return;
}
int mid=l+r>>1;
double a0=0,a1=0,b0=0,b1=0;
for(int i=l;i<=r;i++) {
a0+=a[c[i]].x,b0+=a[c[i]].y;
}
a0/=(r-l+1),b0/=r-l+1;
for(int i=l;i<=r;i++) {
a1+=(a[c[i]].x-a0)*(a[c[i]].x-a0);
b1+=(a[c[i]].y-b0)*(a[c[i]].y-b0);
}
if(a1>b1) {
nth_element(c+l,c+mid,c+r+1,cmpx);
p=c[mid]; a[p].w=0;
} else {
nth_element(c+l,c+mid,c+r+1,cmpy);
p=c[mid]; a[p].w=1;
}
bld(ls[p],l,mid-1),bld(rs[p],mid+1,r);
up(p);
}
int tot;
queue<int>Q;
inline void rebld(int &p) {
tot=0;
Q.push(p); int u;
while(!Q.empty()) {
u=Q.front(); Q.pop();
c[++tot]=u;
if(ls[u]) Q.push(ls[u]);
if(rs[u]) Q.push(rs[u]);
}
bld(p,1,tot);
}
void ins(int &p,int x) {
if(!p) {
p=x; up(p); return;
}
if(a[p].w==0) {
if(a[p].x>=a[x].x) ins(ls[p],x);
else ins(rs[p],x);
} else {
if(a[p].y>=a[x].y) ins(ls[p],x);
else ins(rs[p],x);
}
up(p);
if(0.75*sz[p]<=max(sz[ls[p]],sz[rs[p]])) {
rebld(p);
}
}
inline int gz(int p) {
return max(0,a[p].l[0]-qx)+max(0,qx-a[p].r[0])+max(0,a[p].l[1]-qy)+max(0,qy-a[p].r[1]);
}
void ask(int p) {
ans=min(ans,abs(a[p].x-qx)+abs(a[p].y-qy));
int x=INF,y=INF;
if(ls[p]) x=gz(ls[p]);
if(rs[p]) y=gz(rs[p]);
if(x<y) {
if(x<ans) ask(ls[p]);
if(y<ans) ask(rs[p]);
} else {
if(y<ans) ask(rs[p]);
if(x<ans) ask(ls[p]);
}
}
int main(){
n=rd(); int T=rd();
for(int i=1;i<=n;i++) {
c[i]=i; a[i].x=rd(),a[i].y=rd();
}
bld(rt,1,n);
while(T--) {
int op=rd();
if(op==1) {
a[++n].x=rd(),a[n].y=rd();
ins(rt,n);
} else {
qx=rd(),qy=rd();
ans=INF;
ask(rt);
printf("%d\n",ans);
}
}
return 0;
}
线段树上的节点标号表示在序列中的编号,c[i]表示在序列中的编号
注意:插入后要及时up,插入中也要up,bld中也要up,不要忘记
例题1
用堆维护
注意求K远点,估值函数需要调整
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int rd() {
int ret=0; char ch=getchar(); bool fl=0;
for(;!isdigit(ch);ch=getchar()) fl=(ch=='-');
for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-'0';
return fl?-ret:ret;
}
const int N=1e6+5;
int n,m,ls[N],rs[N],c[N],qx,qy,ans,rt;
struct A{
int x,y,l[2],r[2],w;
}a[N];
struct B{int id; ll x; };
bool operator >(B i,B j) {
return i.x>j.x||i.x==j.x&&i.id<j.id;
}
priority_queue<B,vector<B>,greater<B> >q;
inline bool cmpx(int i,int j) {
return a[i].x<a[j].x;
}
inline bool cmpy(int i,int j) {
return a[i].y<a[j].y;
}
inline void up(int p) {
a[p].l[0]=a[p].r[0]=a[p].x;
a[p].l[1]=a[p].r[1]=a[p].y;
if(ls[p]) {
a[p].l[0]=min(a[p].l[0],a[ls[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[ls[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[ls[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[ls[p]].r[1]);
}
if(rs[p]) {
a[p].l[0]=min(a[p].l[0],a[rs[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[rs[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[rs[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[rs[p]].r[1]);
}
}
inline void bld(int &p,int l,int r) {
if(l>r) {
p=0; return;
}
int mid=l+r>>1;
double a0=0,a1=0,b0=0,b1=0;
for(int i=l;i<=r;i++) {
a0+=a[c[i]].x,b0+=a[c[i]].y;
}
a0/=(r-l+1),b0/=r-l+1;
for(int i=l;i<=r;i++) {
a1+=(a[c[i]].x-a0)*(a[c[i]].x-a0);
b1+=(a[c[i]].y-b0)*(a[c[i]].y-b0);
}
if(a1>b1) {
nth_element(c+l,c+mid,c+r+1,cmpx);
p=c[mid]; a[p].w=0;
} else {
nth_element(c+l,c+mid,c+r+1,cmpy);
p=c[mid]; a[p].w=1;
}
bld(ls[p],l,mid-1),bld(rs[p],mid+1,r);
up(p);
}
inline ll gz(int p) {
return (ll)max(0,a[p].r[0]-qx)*max(0,a[p].r[0]-qx)+(ll)max(0,qx-a[p].l[0])*max(0,qx-a[p].l[0])+(ll)max(0,a[p].r[1]-qy)*max(0,a[p].r[1]-qy)+(ll)max(0,qy-a[p].l[1])*max(0,qy-a[p].l[1]);
}
void ask(int p) {
ll D=(ll)(qx-a[p].x)*(qx-a[p].x)+(ll)(qy-a[p].y)*(qy-a[p].y);
if(q.top().x<D||q.top().x==D&&p<q.top().id) {
q.pop();
q.push((B){p,D});
}
ll x=-2,y=-2;
if(ls[p]) x=gz(ls[p]);
if(rs[p]) y=gz(rs[p]);
if(x>y) {
if(x>=q.top().x) ask(ls[p]);
if(y>=q.top().x) ask(rs[p]);
} else {
if(y>=q.top().x) ask(rs[p]);
if(x>=q.top().x) ask(ls[p]);
}
}
int main(){
n=rd();
for(int i=1;i<=n;i++) {
c[i]=i; a[i].x=rd(),a[i].y=rd();
}
bld(rt,1,n);
int T=rd();
while(T--) {
qx=rd(),qy=rd(); int k=rd();
for(int i=1;i<=k;i++) q.push((B){0,-1});
ask(rt);
printf("%d\n",q.top().id);
for(int i=1;i<=k;i++) q.pop();
}
return 0;
}
例题2
把二维的点当作点
尝试最优的dfs即可(剪枝越多越好)
#include<bits/stdc++.h>
const int INF=1e9;
using namespace std;
inline int rd() {
int ret=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-'0';
return ret;
}
const int N=2e5+5;
int n,m,ls[N],rs[N],sz[N],c[N],qx,qy,k,ans,rt;
struct A{
int x,y,l[2],r[2],w,s,c;
}a[N];
inline bool cmpx(int i,int j) {
return a[i].x<a[j].x;
}
inline bool cmpy(int i,int j) {
return a[i].y<a[j].y;
}
inline void up(int p) {
sz[p]=sz[ls[p]]+sz[rs[p]]+1;
a[p].s=a[ls[p]].s+a[rs[p]].s+a[p].c;
a[p].l[0]=a[p].r[0]=a[p].x;
a[p].l[1]=a[p].r[1]=a[p].y;
if(ls[p]) {
a[p].l[0]=min(a[p].l[0],a[ls[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[ls[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[ls[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[ls[p]].r[1]);
}
if(rs[p]) {
a[p].l[0]=min(a[p].l[0],a[rs[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[rs[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[rs[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[rs[p]].r[1]);
}
}
inline void bld(int &p,int l,int r) {
if(l>r) {
p=0; return;
}
int mid=l+r>>1;
double a0=0,a1=0,b0=0,b1=0;
for(int i=l;i<=r;i++) {
a0+=a[c[i]].x,b0+=a[c[i]].y;
}
a0/=(r-l+1),b0/=r-l+1;
for(int i=l;i<=r;i++) {
a1+=(a[c[i]].x-a0)*(a[c[i]].x-a0);
b1+=(a[c[i]].y-b0)*(a[c[i]].y-b0);
}
if(a1>b1) {
nth_element(c+l,c+mid,c+r+1,cmpx);
p=c[mid]; a[p].w=0;
} else {
nth_element(c+l,c+mid,c+r+1,cmpy);
p=c[mid]; a[p].w=1;
}
bld(ls[p],l,mid-1),bld(rs[p],mid+1,r);
up(p);
}
int tot,u;
queue<int>Q;
inline void rebld(int &p) {
tot=0,Q.push(p);
while(!Q.empty()) {
u=Q.front(); Q.pop();
c[++tot]=u;
if(ls[u]) Q.push(ls[u]);
if(rs[u]) Q.push(rs[u]);
}
bld(p,1,tot);
}
void ins(int &p) {
if(!p) {
a[++n].x=qx,a[n].y=qy,a[n].c=k,p=n; up(p);
return;
}
if(a[p].x==qx&&a[p].y==qy) {
a[p].c+=k; up(p);
return;
}
if(a[p].w==0) {
if(a[p].x>=qx) ins(ls[p]);
else ins(rs[p]);
} else {
if(a[p].y>=qy) ins(ls[p]);
else ins(rs[p]);
}
up(p);
if(0.75*sz[p]<=max(sz[ls[p]],sz[rs[p]])) {
rebld(p);
}
}
int x1,Y1,x2,y2;
void ask(int p) {
if(x1>a[p].r[0]||x2<a[p].l[0]||Y1>a[p].r[1]||y2<a[p].l[1]) {
return;
}
if(x1<=a[p].l[0]&&a[p].r[0]<=x2&&Y1<=a[p].l[1]&&a[p].r[1]<=y2) {
ans+=a[p].s; return;
}
if(x1<=a[p].x&&a[p].x<=x2&&Y1<=a[p].y&&a[p].y<=y2) {
ans+=a[p].c;
}
ask(ls[p]),ask(rs[p]);
}
int main(){
rd(); int op;
while((op=rd())!=3) {
if(op==1) {
qx=rd()^ans,qy=rd()^ans,k=rd()^ans;
ins(rt);
} else {
x1=rd()^ans,Y1=rd()^ans,x2=rd()^ans,y2=rd()^ans;
ans=0; ask(rt);
printf("%d\n",ans);
}
}
return 0;
}
注意:y1不能为变量,好像是C++自带的指针?
例题3
子树,可以看作\(dfn[u]\in[dfn[v],dfn[v]+sz[v])\)
不超过\(l\),可以看作\(dep[u]\in[dep[v],dep[v]+l]\)
所以可以将每个点看作\((dfn[u],dep[u])\),二维修改,二维查询
树套树空间不允许,所以kd-tree
#include<bits/stdc++.h>
#define ll long long
const int INF=1e9;
const int P=1e9+7;
using namespace std;
inline int rd() {
int ret=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-'0';
return ret;
}
const int N=1e5+5;
int n,m,ls[N],rs[N],sz[N],c[N],rt;
struct A{
int x,y,c,l[2],r[2],w,t;
}a[N];
vector<int>V[N];
inline bool cmpx(int i,int j) {
return a[i].x<a[j].x||a[i].x==a[j].x&&a[i].y<a[j].y;
}
inline bool cmpy(int i,int j) {
return a[i].y<a[j].y||a[i].y==a[j].y&&a[i].x<a[j].x;
}
inline void up(int p) {
a[p].l[0]=a[p].r[0]=a[p].x;
a[p].l[1]=a[p].r[1]=a[p].y;
if(ls[p]) {
a[p].l[0]=min(a[p].l[0],a[ls[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[ls[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[ls[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[ls[p]].r[1]);
}
if(rs[p]) {
a[p].l[0]=min(a[p].l[0],a[rs[p]].l[0]);
a[p].l[1]=min(a[p].l[1],a[rs[p]].l[1]);
a[p].r[0]=max(a[p].r[0],a[rs[p]].r[0]);
a[p].r[1]=max(a[p].r[1],a[rs[p]].r[1]);
}
}
inline void bld(int &p,int l,int r) {
if(l>r) {
p=0; return;
}
int mid=l+r>>1;
double a0=0,a1=0,b0=0,b1=0;
for(int i=l;i<=r;i++) {
a0+=a[c[i]].x,b0+=a[c[i]].y;
}
a0/=(r-l+1),b0/=r-l+1;
for(int i=l;i<=r;i++) {
a1+=(a[c[i]].x-a0)*(a[c[i]].x-a0);
b1+=(a[c[i]].y-b0)*(a[c[i]].y-b0);
}
if(a1>b1) {
nth_element(c+l,c+mid,c+r+1,cmpx);
p=c[mid]; a[p].w=0;
} else {
nth_element(c+l,c+mid,c+r+1,cmpy);
p=c[mid]; a[p].w=1;
}
bld(ls[p],l,mid-1),bld(rs[p],mid+1,r);
a[p].c=1,a[p].t=0;
up(p);
}
int tot;
void dfs(int u) {
a[u].x=++tot,sz[u]=1; c[u]=u;
for(auto v:V[u]) {
a[v].y=a[u].y+1;
dfs(v);
sz[u]+=sz[v];
}
}
inline void down(int p){
if(a[p].t) {
if(ls[p]) {
a[ls[p]].c=a[ls[p]].t=a[p].t;
}
if(rs[p]) {
a[rs[p]].c=a[rs[p]].t=a[p].t;
}
a[p].t=0;
}
}
void upd(int p,int x1,int Y1,int x2,int y2,int k) {
if(a[p].l[0]>x2||a[p].r[0]<x1||Y1>a[p].r[1]||y2<a[p].l[1]) {
return;
}
if(x1<=a[p].l[0]&&a[p].r[0]<=x2&&Y1<=a[p].l[1]&&a[p].r[1]<=y2) {
a[p].c=k,a[p].t=k; return;
}
down(p);
if(x1<=a[p].x&&a[p].x<=x2&&Y1<=a[p].y&&a[p].y<=y2) {
a[p].c=k;
}
upd(ls[p],x1,Y1,x2,y2,k),upd(rs[p],x1,Y1,x2,y2,k);
}
int ask(int p,int x) {
if(p==x) {
return a[p].c;
}
down(p);
if(a[p].w==0) {
if(a[p].x>a[x].x) return ask(ls[p],x);
return ask(rs[p],x);
} else {
if(a[p].y>a[x].y||a[p].y==a[x].y&&a[p].x>a[x].x) return ask(ls[p],x);
return ask(rs[p],x);
}
}
int main(){
int T=rd();
while(T--) {
n=rd(),rd(),m=rd();
for(int i=1;i<=n;i++) {
V[i].clear();
vector<int>().swap(V[i]);
}
for(int i=2;i<=n;i++) {
V[rd()].push_back(i);
}
tot=0; dfs(1);
bld(rt,1,n);
int ans=0;
for(int i=1;i<=m;i++) {
int u=rd(),l=rd(),k=rd();
if(k!=0) {
upd(rt,a[u].x,a[u].y,a[u].x+sz[u]-1,a[u].y+l,k);
} else {
ans=((ll)i*ask(rt,u)+ans)%P;
}
}
printf("%d\n",ans);
}
return 0;
}

KD-tree
浙公网安备 33010602011771号