题意:维护二维平面上的点集,支持插入一个点,查询点集中的点到指定点的最小、最大曼哈顿距离。不强制在线,n,m<=10w。
考试的时候没怎么动脑子,直接上分象限讨论+线段树套平衡树,花了2h写了7k结果常数太大只得了50分。
为了降低常数,采用cdq分治。有一个特殊的技巧,就是不需要按象限分类,只讨论x,y都比当前小的情况,其他情况可以将坐标轴对称四次得到。按x坐标排序,然后按时间来划分,用树状数组来维护y的前缀最值。然后为了卡常注意在分治内部遇到没有询问,或者不可能产生贡献的区间就提前跳出。
以后不强制在线的三维偏序干脆直接上cdq啊!又快内存又小还好写。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int MAXN = 100005;
const int inf = 0x3f3f3f3f;
inline void gmin(int&a, const int&b) { if(a>b) a=b; }
inline void gmax(int&a, const int&b) { if(a<b) a=b; }
template<typename T>
void get(T&x) {
char c; x = 0;
do c=getchar(); while (c<'0'||c>'9');
do x=x*10+c-'0',c=getchar(); while (c>='0'&&c<='9');
}
int N, Q, pn;
int op[MAXN], ox[MAXN], oy[MAXN], ans[MAXN];
int daty[MAXN*2], yn;
int idxy(int y) { return lower_bound(daty+1, daty+yn+1, y) - daty; }
struct dot {
int x, y, t, loc, xi, yi;
dot () {}
dot (int a, int b, int c, int d) : x(a), y(b), t(c), loc(d) {}
} a[MAXN * 2], po[MAXN * 2];
bool cmpx(const dot&a, const dot&b)
{ return a.x!=b.x ? a.x<b.x : a.y<b.y; }
int bd = 100000005;
int c1[MAXN*2], c2[MAXN*2]; //c1保存前缀最小值,c2存前缀最大值,按离散后的y坐标排序。
void set1(int *c, int i, int v)
{
for (; i<=yn; i+=i&-i)
if (v < c[i]) c[i] = v;
}
void set2(int *c, int i, int v)
{
for (; i<=yn; i+=i&-i)
if (v > c[i]) c[i] = v;
}
int qmax(int *c, int i)
{
int r = -inf;
for (; i>0; i-=i&-i)
if (r<c[i]) r = c[i];
return r;
}
int qmin(int *c, int i)
{
int r = inf;
for (; i>0; i-=i&-i)
if (r>c[i]) r = c[i];
return r;
}
void cdq(int L, int R)
{
if (L == R) return;
int mid = (L+R)>>1, l1 = L, l2 = mid+1;
int ql = 0, qr = 0;
rep(i, L, R)
{
if (a[i].t <= mid) { po[l1++] = a[i]; if (a[i].loc) ++ql; }
else { po[l2++] = a[i]; if (a[i].loc) ++qr; }
}
if (!qr || !(mid-L+1-ql)) return;
rep(i, L, R) a[i] = po[i];
int i = L, j = mid+1;
for (; j<=R; ++j)
{
for (; a[i].x <= a[j].x && i <= mid; ++i)
{
if (a[i].loc) continue;
set1(c1, a[i].yi, a[i].x + a[i].y);
set2(c2, a[i].yi, a[i].x + a[i].y);
}
if (op[a[j].loc] == 1) gmin(ans[a[j].loc], a[j].x + a[j].y - qmax(c2, a[j].yi));
if (op[a[j].loc] == 2) gmax(ans[a[j].loc], a[j].x + a[j].y - qmin(c1, a[j].yi));
}
for (; i>=L; --i) if (!a[i].loc) set2(c1, a[i].yi, inf), set1(c2, a[i].yi, -inf);
if (ql) cdq(L, mid);
if (qr) cdq(mid+1, R);
}
void solve()
{
yn = 0;
rep(i, 1, pn) daty[++yn] = a[i].y;
sort(daty+1, daty+yn+1);
yn = unique(daty+1, daty+yn+1) - daty-1;
rep(i, 1, yn) c1[i] = inf, c2[i] = -inf;
sort(a+1, a+pn+1, cmpx);
rep(i, 1, pn) a[i].yi = idxy(a[i].y);
cdq(1, pn);
}
int main()
{
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
get(N);
rep(i, 1, N) get(a[i].x), get(a[i].y), a[i].t = i;
get(Q); pn = N;
rep(i, 1, Q)
{
get(op[i]), get(ox[i]), get(oy[i]);
++pn, a[pn] = dot(ox[i], oy[i], pn, op[i] ? i : 0);
if (op[i]==1) ans[i] = inf;
else if (op[i]==2) ans[i] = -inf;
}
solve();
rep(i, 1, pn) a[i].x = bd - a[i].x;
solve();
rep(i, 1, pn) a[i].y = bd - a[i].y;
solve();
rep(i, 1, pn) a[i].x = bd - a[i].x;
solve();
rep(i, 1, Q) if (op[i]) printf("%d\n", ans[i]);
return 0;
}
考试时候写的250行7k结果常数爆炸的树套树,留个纪念吧23333
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
#define idx(L,R) ((L+R)|(L!=R))
using namespace std;
const int MAXN = 100005, MAXS = MAXN*50;
const int inf = 0x3f3f3f3f;
template<typename T>
void get(T&x) {
char c; x = 0;
do c=getchar(); while (c<'0'||c>'9');
do x=x*10+c-'0',c=getchar(); while (c>='0'&&c<='9');
}
int N, Q;
int dat[MAXN*2], dn;
int xp[MAXN], yp[MAXN];
int op[MAXN], ox[MAXN], oy[MAXN];
inline int bh(int v) { return lower_bound(dat+1, dat+dn+1, v)-dat; }
int ran()
{
static int sd = 1237;
return sd = (sd*1237)&0x7fffffff;
}
#define lch(x) ch[x][0]
#define rch(x) ch[x][1]
int root[MAXN*4];
namespace Treap
{
int ch[MAXS][2], vx[MAXS], vy[MAXS], fix[MAXS], ncnt;
int mx1[MAXS], mx2[MAXS], mi1[MAXS], mi2[MAXS];
void init()
{
mx1[0] = -inf, mx2[0] = -inf;
mi1[0] = inf, mi2[0] = inf;
}
inline void pushup(int&x)
{
mx1[x] = mi1[x] = vx[x] + vy[x];
mx2[x] = mi2[x] = vx[x] - vy[x];
mx1[x] = max(mx1[x], max(mx1[lch(x)], mx1[rch(x)]));
mi1[x] = min(mi1[x], min(mi1[lch(x)], mi1[rch(x)]));
mx2[x] = max(mx2[x], max(mx2[lch(x)], mx2[rch(x)]));
mi2[x] = min(mi2[x], min(mi2[lch(x)], mi2[rch(x)]));
}
inline void rotate(int&x, const int&d)
{
int y = ch[x][!d];
ch[x][!d] = ch[y][d];
ch[y][d] = x;
pushup(x), pushup(x = y);
}
inline int NewNode(const int&tx, const int&ty)
{
vx[++ncnt] = tx, vy[ncnt] = ty;
fix[ncnt] = ran();
mx1[ncnt] = mi1[ncnt] = vx[ncnt] + vy[ncnt];
mx2[ncnt] = mi2[ncnt] = vx[ncnt] - vy[ncnt];
return ncnt;
}
inline void ins0(int&x, const int&tx, const int&ty)
{
if (!x) { x = NewNode(tx,ty), fix[x] = (MAXS-ncnt)<<4; return; }
int d = (ty>vy[x]);
ins0(ch[x][d], tx, ty), pushup(x);
}
inline void ins(int&x, const int&tx, const int&ty)
{
if (!x) { x = NewNode(tx,ty); return; }
int d = (ty>vy[x]);
ins(ch[x][d], tx, ty);
if (fix[ch[x][d]] > fix[x]) rotate(x, !d);
pushup(x);
}
inline int ask1(int &x, const int&ty) //查找y>=ty的最大x+y
{
if (!x) return -inf;
if (vy[x] < ty) return ask1(rch(x), ty);
return max(max(mx1[rch(x)], vx[x]+vy[x]), ask1(lch(x), ty));
}
inline int ask2(int &x, const int&ty) //查找y>=ty的最小x+y
{
if (!x) return inf;
if (vy[x] < ty) return ask2(rch(x), ty);
return min(min(mi1[rch(x)], vx[x]+vy[x]), ask2(lch(x), ty));
}
inline int ask3(int &x, const int&ty) //查找y<ty的最大x-y
{
if (!x) return -inf;
if (vy[x] >= ty) return ask3(lch(x), ty);
return max(max(mx2[lch(x)], vx[x]-vy[x]), ask3(rch(x), ty));
}
inline int ask4(int &x, const int&ty) //查找y<ty的最小x-y
{
if (!x) return inf;
if (vy[x] >= ty) return ask4(lch(x), ty);
return min(min(mi2[lch(x)], vx[x]-vy[x]), ask4(rch(x), ty));
}
inline int ask5(int &x, const int&ty) //查找y>=ty的最大x-y
{
if (!x) return -inf;
if (vy[x] < ty) return ask5(rch(x), ty);
return max(max(mx2[rch(x)], vx[x]-vy[x]), ask5(lch(x), ty));
}
inline int ask6(int &x, const int&ty) //查找y>=ty的最小x-y
{
if (!x) return inf;
if (vy[x] < ty) return ask6(rch(x), ty);
return min(min(mi2[rch(x)], vx[x]-vy[x]), ask6(lch(x), ty));
}
inline int ask7(int &x, const int&ty) //查找y<ty的最大x+y
{
if (!x) return -inf;
if (vy[x] >= ty) return ask7(lch(x), ty);
return max(max(mx1[lch(x)], vx[x]+vy[x]), ask7(rch(x), ty));
}
inline int ask8(int &x, const int&ty) //查找y<ty的最小x+y
{
if (!x) return inf;
if (vy[x] >= ty) return ask8(lch(x), ty);
return min(min(mi1[lch(x)], vx[x]+vy[x]), ask8(rch(x), ty));
}
}
void ins0(int xi, int x, int y, int L, int R)
{
Treap::ins0(root[idx(L, R)], x, y);
if (L == R) return;
int mid = (L+R)>>1;
if (xi<=mid) ins0(xi, x, y, L, mid);
else ins0(xi, x, y, mid+1, R);
}
void ins(int xi, int x, int y, int L, int R)
{
Treap::ins(root[idx(L, R)], x, y);
if (L == R) return;
int mid = (L+R)>>1;
if (xi<=mid) ins(xi, x, y, L, mid);
else ins(xi, x, y, mid+1, R);
}
inline int ask1(int xi, int yi, int L, int R) //求x>=xi, y>=yi的最大x+y
{
if (R<xi) return -inf;
if (L>=xi) return Treap::ask1(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return max(ask1(xi, yi, L, mid), ask1(xi, yi, mid+1, R));
}
inline int ask2(int xi, int yi, int L, int R) //求x>=xi, y>=yi的最小x+y
{
if (R<xi) return inf;
if (L>=xi) return Treap::ask2(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return min(ask2(xi, yi, L, mid), ask2(xi, yi, mid+1, R));
}
inline int ask3(int xi, int yi, int L, int R) //求x>=xi, y<yi的最大x-y
{
if (R<xi) return -inf;
if (L>=xi) return Treap::ask3(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return max(ask3(xi, yi, L, mid), ask3(xi, yi, mid+1, R));
}
inline int ask4(int xi, int yi, int L, int R) //求x>=xi, y<yi的最小x-y
{
if (R<xi) return inf;
if (L>=xi) return Treap::ask4(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return min(ask4(xi, yi, L, mid), ask4(xi, yi, mid+1, R));
}
inline int ask5(int xi, int yi, int L, int R) //求x<xi, y>=yi的最大x-y
{
if (L>=xi) return -inf;
if (R<xi) return Treap::ask5(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return max(ask5(xi, yi, L, mid), ask5(xi, yi, mid+1, R));
}
inline int ask6(int xi, int yi, int L, int R) //求x<xi, y>=yi的最小x-y
{
if (L>=xi) return inf;
if (R<xi) return Treap::ask6(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return min(ask6(xi, yi, L, mid), ask6(xi, yi, mid+1, R));
}
inline int ask7(int xi, int yi, int L, int R) //求x<xi, y<yi的最大x+y
{
if (L>=xi) return -inf;
if (R<xi) return Treap::ask7(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return max(ask7(xi, yi, L, mid), ask7(xi, yi, mid+1, R));
}
inline int ask8(int xi, int yi, int L, int R) //求x<xi, y<yi的最小x+y
{
if (L>=xi) return inf;
if (R<xi) return Treap::ask8(root[idx(L, R)], yi);
int mid = (L+R)>>1;
return min(ask8(xi, yi, L, mid), ask8(xi, yi, mid+1, R));
}
inline int solve1(int x, int y) //离它最近的
{
int xi = bh(x);
int r1 = ask2(xi, y, 1, dn) - (x+y);
int r2 = ask4(xi, y, 1, dn) - (x-y);
int r3 = (x-y) - ask5(xi, y, 1, dn);
int r4 = (x+y) - ask7(xi, y, 1, dn);
r2 = min(r2, r1), r3 = min(r3, r2), r4 = min(r4, r3);
return r4;
}
inline int solve2(int x, int y) //离它最远的
{
int xi = bh(x);
int r1 = ask1(xi, y, 1, dn) - (x+y);
int r2 = ask3(xi, y, 1, dn) - (x-y);
int r3 = (x-y) - ask6(xi, y, 1, dn);
int r4 = (x+y) - ask8(xi, y, 1, dn);
r2 = max(r2, r1), r3 = max(r3, r2), r4 = max(r4, r3);
return r4;
}
int main()
{
Treap::init();
get(N);
int u, v;
rep(i, 1, N) get(xp[i]), get(yp[i]), dat[++dn] = xp[i];
rep(i, 1, N) u=ran()%N+1, v=ran()%N+1, swap(xp[u], xp[v]), swap(yp[u], yp[v]);
get(Q);
rep(i, 1, Q) get(op[i]), get(ox[i]), get(oy[i]), dat[++dn] = ox[i];
sort(dat+1, dat+dn+1);
dn = unique(dat+1, dat+dn+1) -dat-1;
rep(i, 1, N) ins0(bh(xp[i]), xp[i], yp[i], 1, dn);
rep(i, 1, Q)
{
if (op[i] == 0) ins(bh(ox[i]), ox[i], oy[i], 1, dn);
else if (op[i] == 1) printf("%d\n", solve1(ox[i], oy[i]));
else printf("%d\n", solve2(ox[i], oy[i]));
}
return 0;
}