数据 (cdq分治)

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


你可能感兴趣的:(数据 (cdq分治))