大锑问题之
1.树上问题,先将子树答案更新后,用新的值更新答案

//可并堆合并
struct MHN{ ll val, lc, rc, sz, dist, sum;} H[100007];
int merge(int x, int y)
{
	if((!x) || (!y)) return x | y;
	if(H[x].val < H[y].val) swap(x, y);
	H[x].sz += H[y].sz;//H[y]会改掉,应该先加完再合并, 100pts
	H[x].sum += H[y].sum;
	H[x].rc = merge(H[x].rc, y);
	if(H[H[x].lc].dist < H[H[x].rc].dist) swap(H[x].lc, H[x].rc);
	H[x].dist = H[H[x].rc].dist + 1;
//	H[x].sz += H[y].sz;//H[y]被改掉, 8pts
//	H[x].sum += H[y].sum;
//  也可以写成这样:
//	H[x].sz = H[H[x].lc].sz + H[H[x].rc].sz + 1;
//	H[x].sum = H[H[x].lc].sum + H[H[x].rc].sum + H[x].val;
	return x;
}

2.重载min使得递归函数计算两遍,减慢时间

//平面最近点对,,,,,这个是错的
#define min(a, b) (((a) < (b))?(a):(b))
ll dfs(int l, int r, int fa)
{
	tot ++;
	int now = tot;
	if(l >= r) return INF;
	if(r == l + 1) return pow(a[l].x - a[r].x) + pow(a[l].y - a[r].y);
	int mi = (l + r) >> 1;
	ll merg = min(dfs(l, mi, now), dfs(mi + 1, r, now)); //左右两侧的最小值
  //--------------WARNING--------------//
 //  递归两遍O(f(n) * n), n的次数++;   //
//--------------WARNING--------------//
	//在竖线左右两侧不能超过merg,才有可能更新答案
	int lp = mi, rp = mi;
	for( ; pow(a[lp - 1].x - a[mi].x) <= merg && lp > l ; lp --);
	for( ; pow(a[rp + 1].x - a[mi].x) <= merg && rp < r ; rp ++);
	sort(b + lp, b + rp + 1, cmpy);
	//双指针
	int i = lp, j = rp;
	while(pow(b[i].y - b[j].y) > merg) j --;
	for(; i <= rp ; i++)
	{
		while(pow(b[i].y - b[j + 1].y) <= merg && j < rp) j ++;
		for(int k = i + 1 ; k <= j ; k++) if(k != i) merg = min(merg, pow(b[i].x - b[k].x) + pow(b[i].y - b[k].y));
	}
	return merg;
}

3.数组在递归之后没还原

//平面最近点对,,,,,这个是对的
ll dfs(int l, int r)
{
	if(l >= r) return INF;
	if(r == l + 1) return pow(a[l].x - a[r].x) + pow(a[l].y - a[r].y);
	int mi = (l + r) >> 1;
	ll lsum = dfs(l, mi), rsum = dfs(mi + 1, r);
	ll merg = min(lsum, rsum); //左右两侧的最小值
	//在竖线左右两侧不能超过merg,才有可能更新答案
	int lp = mi, rp = mi;
	for( ; pow(a[lp - 1].x - a[mi].x) <= merg && lp > l ; lp --);
	for( ; pow(a[rp + 1].x - a[mi].x) <= merg && rp < r ; rp ++);
	sort(b + lp, b + rp + 1, cmpy);
	//双指针
	int i = lp, j = rp;
	while(pow(b[i].y - b[j].y) > merg) j --;
	for(; i <= rp ; i++)
	{
		while(pow(b[i].y - b[j + 1].y) <= merg && j < rp) j ++;
		for(int k = i + 1 ; k <= j ; k++) merg = min(merg, pow(b[i].x - b[k].x) + pow(b[i].y - b[k].y));
	}
	for(int i = l ; i <= r ; i++) b[i] = a[i];
	  //------------------WARNING---------------------//
	 //b数组数字位置会改变,下一次递归时无法获得正确的位置//
	//----------------------------------------------//
	return merg;
}
posted on 2023-09-29 10:50  zsfeng  阅读(8)  评论(0编辑  收藏  举报