大锑问题之
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;
}