题意:维护二维平面上的点集,支持插入一个点,查询点集中的点到指定点的最小、最大曼哈顿距离。不强制在线,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; }