其实理论上cdq更优

核心是依次取x值、y值的mid作为当前节点,向两边递归建立二叉树,树上维护size:子树大小;mx[0/1]:子树内最大x/y;mn[0/1]:子树内最小x/y;d[0/1]:这个点的x/y;

建树的时候用到nth_element,用处是把第k个数放到k位置,并且把小于k的放在k前,大于k的放在k后(算是快排的一部分)

插入点的时候,像走二叉搜索树一样往下走(不过每走一步key值就要变,xy交替),然后走到空就把新点挂上去

查找的时候比较像退火,通过mnmx找到子树能更新答案的最小值预估,然后决定要不要往下走,并且一路走一路用真实值更新答案;如果左右儿子都能走,就先走估值小的那边

然后出现了一个问题,这个插入有可能把二叉树变成一条链,这个时候要用替罪羊树的思想,设一个阈值,如果左右儿子的size比例超过阈值就把这颗子树拍扁重构

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=500005;
const double alp=0.75;
int n,m,w,tot,rt,ans;
struct qwe
{
int a[2];
int& operator [] (int x)
{
return a[x];
}
bool operator < (const qwe &b) const
{
return a[w]<b.a[w];
}
}a[N];
struct KD
{
int s,ls,rs,mn[2],mx[2];
qwe d;
}t[N*5];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void minn(int &x,int y)
{
x>y?x=y:0;
}
void maxx(int &x,int y)
{
x<y?x=y:0;
}
void ud(int ro)
{
if(t[ro].ls)
for(int i=0;i<=1;i++)
minn(t[ro].mn[i],t[t[ro].ls].mn[i]),maxx(t[ro].mx[i],t[t[ro].ls].mx[i]);
if(t[ro].rs)
for(int i=0;i<=1;i++)
minn(t[ro].mn[i],t[t[ro].rs].mn[i]),maxx(t[ro].mx[i],t[t[ro].rs].mx[i]);
t[ro].s=t[t[ro].ls].s+t[t[ro].rs].s+1;
}
int build(int l,int r,int f)
{
if(l>r)
return 0;
w=f;
int mid=(l+r)>>1,ro=++tot;
nth_element(a+l,a+mid,a+r+1);
t[ro].s=1;
t[ro].d[0]=t[ro].mn[0]=t[ro].mx[0]=a[mid][0];
t[ro].d[1]=t[ro].mn[1]=t[ro].mx[1]=a[mid][1];
t[ro].ls=build(l,mid-1,f^1);
t[ro].rs=build(mid+1,r,f^1);
ud(ro);
return ro;
}
void pia(int &ro,int s)
{
if(t[ro].ls)
pia(t[ro].ls,s);
a[s+t[t[ro].ls].s+1]=t[ro].d;
if(t[ro].rs)
pia(t[ro].rs,s+t[t[ro].ls].s+1);
}
void ok(int &ro,int f)
{
if(alp*t[ro].s<max(t[t[ro].ls].s,t[t[ro].rs].s))
pia(ro,0),ro=build(1,t[ro].s,f);
}
void update(int &ro,int x,int y,int f)
{
if(!ro)
{
ro=++tot;
t[ro].s=1;
t[ro].mn[0]=t[ro].mx[0]=t[ro].d[0]=x;
t[ro].mn[1]=t[ro].mx[1]=t[ro].d[1]=y;
return;
}
if(t[ro].d[f]>=(f==0?x:y))
update(t[ro].ls,x,y,f^1);
else
update(t[ro].rs,x,y,f^1);
ud(ro);
ok(ro,f);
}
int dis(int ro,int x,int y)
{
return max(x-t[ro].mx[0],0)+max(t[ro].mn[0]-x,0)+max(y-t[ro].mx[1],0)+max(t[ro].mn[1]-y,0);
}
void ques(int ro,int x,int y)
{
ans=min(ans,abs(x-t[ro].d[0])+abs(y-t[ro].d[1]));
int dl=t[ro].ls?dis(t[ro].ls,x,y):1e9,dr=t[ro].rs?dis(t[ro].rs,x,y):1e9;
if(dl<dr)
{
if(dl<ans)
ques(t[ro].ls,x,y);
if(dr<ans)
ques(t[ro].rs,x,y);
}
else
{
if(dr<ans)
ques(t[ro].rs,x,y);
if(dl<ans)
ques(t[ro].ls,x,y);
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i][0]=read(),a[i][1]=read();
rt=build(1,n,0);
while(m--)
{
int o=read(),x=read(),y=read();
if(o==1)
update(rt,x,y,0);
else
{
ans=1e9;
ques(rt,x,y);
printf("%d\n",ans);
}
}
return 0;
}

最新文章

  1. 【JavaScript】关于prototype
  2. UI1_UIButton
  3. 计算 sql查询语句所花时间
  4. HDU 3336 (KMP next性质) Count the string
  5. 对WM_NCHITTEST消息的了解+代码实例进行演示(消息产生消息,共24个枚举值)
  6. uiautomatorviewer 识别android微信元素报错
  7. python返回null和空的不同
  8. vs打开项目,创建虚拟目录,提示权限不足无法写入配置文件
  9. 剪邮票dfs+bfs+组合+结构体
  10. 设计模式---接口隔离模式之门面模式(Fa&#231;ade)
  11. NET设计模式 第二部分 创建型模式(6):创建型模式专题总结(Creational Pattern)
  12. 【JEECG技术文档】JEECG 接口权限开发及配置使用说明
  13. jQuery的介绍和选择器详解
  14. shell脚本抓取网页信息
  15. #leetcode刷题之路23-合并K个排序链表
  16. 老齐python-基础5(运算符、语句)
  17. CF1067D. Computer Game(斜率优化+倍增+矩阵乘法)
  18. Android-自定义View实现ImageView播放gif
  19. Python基本图形绘制
  20. js HTML DOM TableRow 对象(innerHTML)

热门文章

  1. reorder-list——链表、快慢指针、逆转链表、链表合并
  2. TCP 的那些事儿(下)(转)
  3. ORACLE 8i 遇到报错:ORA-01631: max # extents (505) reached in table
  4. saltstack安装配置(syndic)
  5. Ubuntu 16.04 LTS安装Eclipse配置Pydev
  6. python基础小练习
  7. spi flash 操作
  8. HDOJ_1000
  9. Android — 长按ListView 利用上下文菜单(ActionMode) 进行批量事件处理
  10. POJ 1703 Find them, Catch them(种类并查集)