分析:
本来写的是一开始把所有结点都预先建好,但是T了。
orz了一发题解后发现需要像替罪羊树一样将不平衡的子树重构。
但是不应该是重构深度最小的不平衡的节点为根的子树吗?
代码:
预先开点(TLE)(洛谷AC):
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=300005;
int n,m,qst[MAXN][3],tot;
int root,D;
int qx,qy,ans=1e9;
struct KD_Tree{
int ch[2],fa;
int x,y;
int id;
bool exi;
int xx[2],yy[2];
friend bool operator < (KD_Tree x,KD_Tree y){
if(D==0) return x.x==y.x?x.y<y.y:x.x<y.x;
else return x.y==y.y?x.x<y.x:x.y<y.y;
}
}a[MAXN<<1];
#define mid ((l+r)>>1)
#define lc a[x].ch[0]
#define rc a[x].ch[1]
inline void pushup(int x){
if(x&&a[x].exi){
a[x].xx[0]=min(a[x].xx[0],a[x].x);
a[x].xx[1]=max(a[x].xx[1],a[x].x);
a[x].yy[0]=min(a[x].yy[0],a[x].y);
a[x].yy[1]=max(a[x].yy[1],a[x].y);
}
if(lc){
a[x].xx[0]=min(a[x].xx[0],a[lc].xx[0]);
a[x].xx[1]=max(a[x].xx[1],a[lc].xx[1]);
a[x].yy[0]=min(a[x].yy[0],a[lc].yy[0]);
a[x].yy[1]=max(a[x].yy[1],a[lc].yy[1]);
}
if(rc){
a[x].xx[0]=min(a[x].xx[0],a[rc].xx[0]);
a[x].xx[1]=max(a[x].xx[1],a[rc].xx[1]);
a[x].yy[0]=min(a[x].yy[0],a[rc].yy[0]);
a[x].yy[1]=max(a[x].yy[1],a[rc].yy[1]);
}
}
int buildKD(int l,int r,int d){
if(l>r) return 0;
D=d;nth_element(a+l,a+mid,a+r+1);
a[mid].ch[0]=buildKD(l,mid-1,d^1);
a[mid].ch[1]=buildKD(mid+1,r,d^1);
if(a[mid].ch[0]) a[a[mid].ch[0]].fa=mid;
if(a[mid].ch[1]) a[a[mid].ch[1]].fa=mid;
pushup(mid);
return mid;
}
inline void Insert(int x){
a[x].exi=1;int y=x;pushup(y);
while(a[y].fa) pushup(y=a[y].fa);
}
inline int Evaluate(int x){
if(!x||a[x].xx[0]>a[x].xx[1]) return 1e9;
return (abs(qx-a[x].xx[0])+abs(qx-a[x].xx[1])-(a[x].xx[1]-a[x].xx[0]))/2+
(abs(qy-a[x].yy[0])+abs(qy-a[x].yy[1])-(a[x].yy[1]-a[x].yy[0]))/2;
}
void query(int x){
if(!x||Evaluate(x)>=ans) return;
if(a[x].exi) ans=min(ans,abs(qx-a[x].x)+abs(qy-a[x].y));
if(Evaluate(lc)<Evaluate(rc)) query(lc),query(rc);
else query(rc),query(lc);
}
#undef mid
#undef lc
#undef rc
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
a[i].x=read(),a[i].y=read();
a[i].xx[0]=a[i].xx[1]=a[i].x;
a[i].yy[0]=a[i].yy[1]=a[i].y;
a[i].exi=1;
}
tot=n;
for(int i=1;i<=m;i++){
qst[i][0]=read();
qst[i][1]=read();
qst[i][2]=read();
if(qst[i][0]==1){
tot++;
a[tot].x=qst[i][1],a[tot].y=qst[i][2];
a[tot].xx[0]=a[tot].yy[0]=1e9;
a[tot].xx[1]=a[tot].yy[1]=-1;
a[tot].exi=0;a[tot].id=i;
}
}
root=buildKD(1,tot,0);
for(int i=1;i<=tot;i++) qst[a[i].id][1]=i;
for(int i=1;i<=m;i++){
if(qst[i][0]==1) Insert(qst[i][1]);
else{
qx=qst[i][1],qy=qst[i][2];
ans=1e9;query(root);
printf("%d\n",ans);
}
}
return 0;
}
带重构(洛谷题解):
#include<bits/stdc++.h>
using namespace std;
int read() {
int q=0,w=1;char ch=' ';
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q*w;
}
#define alph (0.75)
const int N=1000005;
struct point{int x[2];}p[N];
struct node{int mi[2],mx[2],ls,rs,sz;point tp;}tr[N];
int n,m,rt,cur,top,WD,ans,rub[N];
int operator < (point a,point b) {return a.x[WD]<b.x[WD];}
int newnode() {//建立新节点
if(top) return rub[top--];
else return ++cur;
}
void up(int k) {
int l=tr[k].ls,r=tr[k].rs;
for(int i=0;i<=1;++i) {
tr[k].mi[i]=tr[k].mx[i]=tr[k].tp.x[i];
if(l) tr[k].mi[i]=min(tr[k].mi[i],tr[l].mi[i]),tr[k].mx[i]=max(tr[k].mx[i],tr[l].mx[i]);
if(r) tr[k].mi[i]=min(tr[k].mi[i],tr[r].mi[i]),tr[k].mx[i]=max(tr[k].mx[i],tr[r].mx[i]);
}
tr[k].sz=tr[l].sz+tr[r].sz+1;
}
int build(int l,int r,int wd) {
if(l>r) return 0;
int k=newnode(),mid=(l+r)>>1;
WD=wd,nth_element(p+l,p+mid,p+r+1),tr[k].tp=p[mid];
//nth_element:使得序列某一位置x(此处是p+mid)是该序列的第x大数
tr[k].ls=build(l,mid-1,wd^1),tr[k].rs=build(mid+1,r,wd^1);
up(k);return k;
}
void pia(int k,int num) {//拍扁
if(tr[k].ls) pia(tr[k].ls,num);
p[num+tr[tr[k].ls].sz+1]=tr[k].tp,rub[++top]=k;
if(tr[k].rs) pia(tr[k].rs,num+tr[tr[k].ls].sz+1);
}
void check(int &k,int wd) {//检查子树是否不平衡
if(alph*tr[k].sz<tr[tr[k].ls].sz||alph*tr[k].sz<tr[tr[k].rs].sz)
pia(k,0),k=build(1,tr[k].sz,wd);
}
void ins(point tmp,int &k,int wd) {//插入
if(!k) {k=newnode(),tr[k].tp=tmp,tr[k].ls=tr[k].rs=0,up(k);return;}
if(tr[k].tp.x[wd]<tmp.x[wd]) ins(tmp,tr[k].rs,wd^1);
else ins(tmp,tr[k].ls,wd^1);
up(k),check(k,wd);//记得在check之前要先pushup
}
int getdis(point tmp,int k) {//获得当前点到矩形的曼哈顿距离
int re=0;
for(int i=0;i<=1;++i)
re+=max(0,tmp.x[i]-tr[k].mx[i])+max(0,tr[k].mi[i]-tmp.x[i]);
return re;
}
int dist(point a,point b) {return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]);}
void query(point tmp,int k) {//查询
ans=min(ans,dist(tmp,tr[k].tp));
int dl=INT_MAX,dr=INT_MAX;
if(tr[k].ls) dl=getdis(tmp,tr[k].ls);
if(tr[k].rs) dr=getdis(tmp,tr[k].rs);
if(dl<dr) {
if(dl<ans) query(tmp,tr[k].ls);
if(dr<ans) query(tmp,tr[k].rs);
}
else {
if(dr<ans) query(tmp,tr[k].rs);
if(dl<ans) query(tmp,tr[k].ls);
}
}
int main() {
int bj;
n=read(),m=read();
for(int i=1;i<=n;++i) p[i].x[0]=read(),p[i].x[1]=read();
rt=build(1,n,0);
while(m--) {
point tmp;
bj=read(),tmp.x[0]=read(),tmp.x[1]=read();
if(bj==1) ins(tmp,rt,0);
else ans=INT_MAX,query(tmp,rt),printf("%d\n",ans);
}
return 0;
}