• bzoj 2648 SJY摆棋子


    bzoj 2648 SJY摆棋子

    • 钱限题.题面可以看这里.
    • 若对每个点都算一遍距离,显然 (T) 爆,在此思想基础上使用 (kd-tree) 配合估价函数来剪枝效果较好.
    • 具体来说,对于 (kd-tree) 上的一个节点,我们知道它这颗子树所管辖的范围,算出我们查询的节点到这个范围内可能的最小距离(下界),若这个距离都比当前记录的答案劣或相等,再搜索这颗子树显然没有意义.
    • 这样就完成了最优性剪枝.
    • 还有一个剪枝,若左子树的距离下界小于右子树的距离下界,则应先搜索左子树,否则先搜索右子树.
    • 感性理解一下,若一个儿子的距离下界小,先搜索它,答案更有可能变得更小,如果小于或等于了另一个儿子的距离下界,就没有必要再搜另一个了
    • 对于加点的操作,就和二叉搜索树一样,从根节点往下,通过比较确定往哪边走,走到适当的位置插入即可.迭代代替递归,常数较小,但要注意走的同时用新节点更新当前节点的信息.
    • 插入过多时,由于 (kd-tree) 无法进行旋转操作保持平衡,树高可能会变得很大,使其退化成链,有三种方法处理.
      • 1.记录一个平衡因子 (alpha) ,像替罪羊树那样,及时拍扁重构.这样写最稳定,时间上(应该是)最优的.
      • 2.不及时重构,每加入一定量的节点后对整棵树重构,这个量大概在 (10^4) 级别,可自行调整.这样写不太稳定,但实现非常简单,只多了几行.
      • 3.离线处理,将所有加点操作都读进来,一开始就全部建好,给每个点加个标记表示是否已经被插入(可用),真正插入时修改标记.这种写法不太推荐,每种操作都要额外考虑标记问题,比较繁琐,而且在资瓷离线的情况下,使用一些离线算法,编写难度和时间效率都远胜于 (kd-tree) .

    (kd-tree) 最近点问题下大概是 (O(玄学)) , 处理矩形问题下最坏是 (O(kn^{1-frac 1 k})) ???不会证明,有 (dalao) 得到了证明或证伪麻烦告知...

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define mp make_pair
    #define pii pair<int,int>
    inline int read()
    {
    	int x=0;
    	bool pos=1;
    	char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())
    		if(ch=='-')
    			pos=0;
    	for(;isdigit(ch);ch=getchar())
    		x=x*10+ch-'0';
    	return pos?x:-x;
    }
    const int MAXN=5e5+10;
    int n,m,Dimen;
    int rt,K=25000;
    struct node{
    	int v[2];
    	int mi[2],ma[2];
    	int ls,rs;
    	bool operator < (const node &rhs) const
    		{
    			return v[Dimen]<rhs.v[Dimen]; 
    		}
    }Tree[MAXN<<1],A[MAXN<<1];
    #define root Tree[o]
    #define lson Tree[root.ls]
    #define rson Tree[root.rs]
    #define inf 1e9
    void init()
    {
    	for(int i=0;i<2;++i)
    		{
    			Tree[0].mi[i]=inf;
    			Tree[0].ma[i]=-inf;
    		}
    }
    inline void pushup(int o)
    {
    	for(int i=0;i<2;++i)
    		{
    			root.mi[i]=min(root.mi[i],min(lson.mi[i],rson.mi[i]));
    			root.ma[i]=max(root.ma[i],max(lson.ma[i],rson.ma[i]));
    		}
    }
    int BuildTree(int l,int r,int dimen)
    {
    	Dimen=dimen;
    	int mid=(l+r)>>1;
    	int o=mid;
    	nth_element(A+l,A+mid,A+r+1);
    	for(int i=0;i<2;++i)
    		{
    			root.v[i]=A[mid].v[i];
    			root.mi[i]=root.ma[i]=root.v[i];
    		}
    	root.ls=root.rs=0;
    	if(l<=mid-1)
    		root.ls=BuildTree(l,mid-1,dimen^1);
    	if(mid+1<=r)
    		root.rs=BuildTree(mid+1,r,dimen^1);
    	pushup(o);
    	return o;
    }
    node querynode;
    int ans;//最近距离 
    int estimate(int o)//估计o到querynode的距离 
    {
    	if(!o)
    		return inf;
    	int res=0;
    	for(int i=0;i<2;++i)
    		{
    			if(querynode.v[i]<root.mi[i])
    				res+=root.mi[i]-querynode.v[i];
    			else if(querynode.v[i]>root.ma[i])
    				res+=querynode.v[i]-root.ma[i];
    		}
    	return res;
    }
    void query(int o)
    {
    	int dist=abs(root.v[0]-querynode.v[0])+abs(root.v[1]-querynode.v[1]);//实际距离 
    	ans=min(ans,dist);
    	int dl=estimate(root.ls),dr=estimate(root.rs);
    	if(dl<dr)
    		{
    			if(dl<ans)
    				query(root.ls);
    			if(dr<ans)
    				query(root.rs);
    		}
    	else
    		{
    			if(dr<ans)
    				query(root.rs);
    			if(dl<ans)
    				query(root.ls);
    		}
    }
    void Insert()//像平衡树一样,比较大小向下走,走到合适的地方接上 
    {
    	++n;
    	for(int i=0;i<2;++i)
    		{
    			A[n].v[i]=Tree[n].v[i]=read();
    			Tree[n].mi[i]=Tree[n].ma[i]=Tree[n].v[i];
    		}
    	for(int o=rt,dimen=0;o;dimen^=1)
    		{
    			for(int i=0;i<2;++i)
    				{
    					root.mi[i]=min(root.mi[i],Tree[n].mi[i]);
    					root.ma[i]=max(root.ma[i],Tree[n].ma[i]);
    				}
    			if(Tree[n].v[dimen]<root.v[dimen])
    				{
    					if(root.ls)
    						o=root.ls;
    					else
    						{
    							root.ls=n;
    							return;
    						}
    				}
    			else
    				{
    					if(root.rs)
    						o=root.rs;
    					else
    						{
    							root.rs=n;
    							return;
    						}
    				}
    		}
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;++i)
    		for(int j=0;j<2;++j)
    			A[i].v[j]=read();
    	init();
    	rt=BuildTree(1,n,0);
    	while(m--)
    		{
    			int op=read();
    			if(op==1)
    				{
    					Insert();
    					if(n%K==0)
    						rt=BuildTree(1,n,0);
    				}
    			else
    				{
    					querynode.v[0]=read();
    					querynode.v[1]=read();
    					ans=inf;
    					query(rt);
    					printf("%d
    ",ans);
    				}
    		}
    	return 0;
    }
    
  • 相关阅读:
    派生
    什么是类的继承
    python中一切皆对象
    类之属性查找
    类之 __init__方法

    MySql cmd下的学习笔记 —— 有关分组的操作(group by)
    MySql cmd下的学习笔记 —— 有关select的操作(max, min等常见函数)
    MySql cmd下的学习笔记 —— 有关select的操作(in, and, where, like等等)
    MySql cmd下的学习笔记 —— 有关表的操作(对表的增删改查)
  • 原文地址:https://www.cnblogs.com/jklover/p/10406843.html
Copyright © 2020-2023  润新知