题目链接 BZOJ 2648
前N个点还是比较好处理的,直接利用二叉树的建树来进行处理,关键就是后面的不断插入的M个点,这时候该如何操作来降低复杂度?
这里,我们引入替罪羊树的思想来使得二叉树趋于平衡,那么平衡因子应该如何确定呢?这道题存在一定的卡常,因为总的点数将近1e6了,这样以来,复杂度都不能带大常数了。
所以,我们估一下值,大概在处理了3e5次操作之后就直接进行重构树,保证了生成的二叉树大致上是趋于矮胖矮胖的稳定型。
为什么大致上是3e5呢?要是2e5的时候就重构会RE,递归次数太多了吧。
0 5
1 1 1
1 0 0
1 2 1
1 3 4
2 2 3
ans:2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int read()
{
int x=0; char c = getchar();
while (c<'0' || c>'9') c = getchar();
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x;
}
const int maxN = 1e6 + 7, maxK = 2, K = 2;
int N, M, op;
struct node
{
int d[2];
friend bool operator < (node e1, node e2) { return e1.d[op] < e2.d[op]; }
friend bool operator == (node e1, node e2) { return e1.d[0] == e2.d[0] && e1.d[1] == e2.d[1]; }
inline void In() { for(int i=0; i<K; i++) d[i] = read(); }
} a[maxN], tree[maxN], p;
int root, key[maxN], child[maxN][2], mx[maxN][maxK], mn[maxN][maxK], tot;
inline void pushup(int rt)
{
for(int i=0; i<K; i++)
{
if(child[rt][0] && child[rt][1])
{
mx[rt][i] = max(tree[rt].d[i], max(mx[child[rt][0]][i], mx[child[rt][1]][i]));
mn[rt][i] = min(tree[rt].d[i], min(mn[child[rt][0]][i], mn[child[rt][1]][i]));
}
else if(child[rt][0])
{
mx[rt][i] = max(tree[rt].d[i], mx[child[rt][0]][i]);
mn[rt][i] = min(tree[rt].d[i], mn[child[rt][0]][i]);
}
else if(child[rt][1])
{
mx[rt][i] = max(tree[rt].d[i], mx[child[rt][1]][i]);
mn[rt][i] = min(tree[rt].d[i], mn[child[rt][1]][i]);
}
else mx[rt][i] = mn[rt][i] = tree[rt].d[i];
}
}
void build(int &rt, int l, int r, int father)
{
if(l > r) return;
int mid = HalF; rt = mid;
key[rt] = key[father] ^ 1;
op = key[rt];
nth_element(a + l, a + mid, a + r + 1);
tree[rt] = a[mid];
build(child[rt][0], l, mid - 1, rt);
build(child[rt][1], mid + 1, r, rt);
pushup(rt);
}
bool did = false;
void Insert(int &rt, int fa)
{
if(!rt)
{
rt = ++tot;
tree[rt] = p;
key[rt] = key[fa] ^ 1;
}
else
{
op = key[rt];
Insert(child[rt][tree[rt] < p], rt);
}
pushup(rt);
}
inline int _Dis(node a, node b)
{
int sum = 0;
for(int i=0; i<K; i++) sum += abs(a.d[i] - b.d[i]);
return sum;
}
inline int Fx(int rt)
{
if(!rt) return INF;
int sum = 0;
for(int i=0; i<K; i++) sum += max(0, mn[rt][i] - p.d[i]) + max(0, p.d[i] - mx[rt][i]);
return sum;
}
int ans;
void query(int rt)
{
if(!rt) return;
int dist = _Dis(tree[rt], p);
if(dist < ans) ans = dist;
int dl = Fx(child[rt][0]), dr = Fx(child[rt][1]);
if(dl < dr)
{
if(dl < ans) query(child[rt][0]);
if(dr < ans) query(child[rt][1]);
}
else
{
if(dr < ans) query(child[rt][1]);
if(dl < ans) query(child[rt][0]);
}
}
int main()
{
N = read(); M = read();
for(int i=1; i<=N; i++) a[i].In();
key[0] = 0;
build(root, 1, N, 0); tot = N;
for(int i=1, t; i<=M; i++)
{
t = read();
p.In();
if(t == 1)
{
did = false;
Insert(root, 0);
if(did) a[tot] = p;
if(i % 300000 == 0) build(root, 1, tot, 0);
}
else
{
ans = INF;
query(root);
printf("%d\n", ans);
}
}
return 0;
}