• 【BZOJ】2675: Bomb


    题意:

    给n个点,任选其中3个点(一个点只能取一次),求选出三个点的最大曼哈顿距离之和与最小曼哈顿距离之和(n<=10^5)。

    题解:

    最大曼哈顿距离之和很好求,就是能包围所有点的经过三个点的矩阵周长。
    考虑最小曼哈顿距离之和。
    我们考虑一个点,那么另外两个点会有两种分布。由于对称性,我们只考虑当前枚举的点在右上角、剩下两个点在左下角的情况。如果能求出这种情况的最优值,那么我们可以通过坐标系的旋转,使得剩下的情况也计算到了(这是做出本题的关键)。

    可以发现曼哈顿距离就是包含三个点的最小矩形周长。
    为了方便,我们假设每个点对应的坐标互不相同。(而实际中要考虑三个点或两个点有坐标相同的情况)
    一、当剩下两个点其中一个点不在这个矩形上:
    此时问题可以转化为,我们枚举中间这个点,然后统计
    1、这个点与它的左下角和右上角
    2、这个点与它的左上角和右下角
    这两种情况的答案。
    我们可以按y轴排序然后维护x轴的前缀最值求出一个方向的最值,然后通过坐标系的旋转求出每个方向的最值(注意实际中要讨论点重合的情况)

    二、两个点都在矩阵上:
    我们同样先y轴排序然后从小到大枚举。
    假设右上角的点为1号点,剩下两个点为2、3号点(不必考虑这两个点谁上谁下,因为标号是自己定的..)
    那么可以得到答案是:

    [2(x_1+y_1-(x_2+y_3)) ]

    那么我们用线段树维护一下((x_2+y_3))的最值,即单点更新(y_i)和区间更新(x_i)以及区间查询(x_i+y_i)
    那么问题解决。

    写的时候注意一下情况一中两个点重合的情况(不特判一下会使得左上右下都是重合的另一个点的答案..)

    时间复杂度:(O(nlogn))

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100005, MN=-(~0u>>1), MX=~0u>>1;
    inline int icmp(int a, int b, int w) { return w?min(a, b):max(a, b); }
    int n, ans1=MN, ans2=MX, nbit, nseg, bit[N][2];
    struct ip {
    	int x, y, id;
    	void scan(int _id) {
    		scanf("%d%d", &x, &y);
    		id=_id;
    	}
    }p[N], a[N];
    bool cmpy(const ip &a, const ip &b) { return a.y==b.y?(a.x==b.x?a.id<b.id:a.x<b.x):a.y<b.y; }
    void bitrebuild(int s) {
    	nbit=s;
    	for(int i=1; i<=nbit; ++i) bit[i][0]=MN, bit[i][1]=MX;
    }
    void bitupdate(int x, int s) {
    	for(; x<=nbit; x+=x&-x) bit[x][0]=max(bit[x][0], s), bit[x][1]=min(bit[x][1], s);
    }
    int bitask(int x, int w) {
    	int r=icmp(MN, MX, w^1); for(; x; x-=x&-x) r=icmp(r, bit[x][w], w);
    	return r;
    }
    struct node *null;
    struct node {
    	node *c[2];
    	int x[2], y[2], go[2];
    	void up() {
    		x[0]=max(c[0]->x[0], c[1]->x[0]);
    		x[1]=min(c[0]->x[1], c[1]->x[1]);
    		y[0]=max(c[0]->y[0], c[1]->y[0]);
    		y[1]=min(c[0]->y[1], c[1]->y[1]);
    	}
    	void upd(int g, int w) {
    		if(this==null) return;
    		if(abs(y[w])<MX) x[w]=icmp(x[w], g+y[w], w);
    		go[w]=icmp(go[w], g, w);
    	}
    	void down() {
    		if(go[0]!=MN) c[0]->upd(go[0], 0), c[1]->upd(go[0], 0), go[0]=MN;
    		if(go[1]!=MX) c[0]->upd(go[1], 1), c[1]->upd(go[1], 1), go[1]=MX;
    	}
    	void init() {
    		x[0]=y[0]=go[0]=MN;
    		x[1]=y[1]=go[1]=MX;
    		c[0]=c[1]=null;
    	}
    }Po[N<<2], *iT=Po, *root;
    node *newnode() { iT->init(); return iT++; }
    void seginit() { null=iT++; null->init(); }
    void segrebuild(int l, int r, node *&x) {
    	x=newnode();
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	segrebuild(l, mid, x->c[0]); segrebuild(mid+1, r, x->c[1]);
    }
    void segrebuild(int s) { iT=&Po[1]; nseg=s; segrebuild(1, s, root); }
    int segask(int L, int R, int w, int l, int r, node *x) {
    	if(L<=l && r<=R) return x->x[w];
    	x->down();
    	int mid=(l+r)>>1, ret=icmp(MN, MX, w^1);
    	if(L<=mid) ret=segask(L, R, w, l, mid, x->c[0]);
    	if(mid<R) ret=icmp(ret, segask(L, R, w, mid+1, r, x->c[1]), w);
    	return ret;
    }
    void segupdate1(int p, int s, int l, int r, node *x) {
    	if(l==r) {
    		x->y[0]=max(x->y[0], s);
    		x->y[1]=min(x->y[1], s);
    		return;
    	}
    	x->down();
    	int mid=(l+r)>>1;
    	if(p<=mid) segupdate1(p, s, l, mid, x->c[0]);
    	else segupdate1(p, s, mid+1, r, x->c[1]);
    	x->up();
    }
    void segupdate2(int L, int R, int s, int l, int r, node *x) {
    	if(L<=l && r<=R) {
    		x->upd(s, 0);
    		x->upd(s, 1);
    		return;
    	}
    	x->down();
    	int mid=(l+r)>>1;
    	if(L<=mid) segupdate2(L, R, s, l, mid, x->c[0]);
    	if(mid<R) segupdate2(L, R, s, mid+1, r, x->c[1]);
    	x->up();
    }
    int segask(int x, int w) { return segask(1, x, w, 1, nseg, root); }
    void segupdate1(int s, int x) { segupdate1(x, s, 1, nseg, root); }
    void segupdate2(int s, int x) { segupdate2(x, nseg, s, 1, nseg, root); }
    void readin() {
    	scanf("%d", &n);
    	for(int i=1; i<=n; ++i)
    		p[i].scan(i);
    }
    int pos[N], cnt;
    void lisan() {
    	static int ax[N];
    	for(int i=1; i<=n; ++i) ax[i]=a[i].x;
    	sort(ax+1, ax+1+n);
    	cnt=unique(ax+1, ax+1+n)-ax-1;
    	sort(a+1, a+1+n, cmpy);
    	for(int i=1; i<=n; ++i) pos[i]=lower_bound(ax+1, ax+1+cnt, a[i].x)-ax;
    }
    void getans1(int d[N][2]) {
    	bitrebuild(cnt);
    	for(int i=1; i<=n; ++i) {
    		int ps=pos[i];
    		d[a[i].id][0]=bitask(ps, 0),
    		d[a[i].id][1]=bitask(ps, 1);
    		bitupdate(ps, a[i].x+a[i].y);
    	}
    }
    void getans2() {
    	segrebuild(cnt);
    	for(int i=1; i<=n; ++i) {
    		int ps=pos[i], x=a[i].x, y=a[i].y, temp;
    		temp=segask(ps, 1); if(temp!=MX) ans1=max(ans1, (x+y-temp)<<1);
    		temp=segask(ps, 0); if(temp!=MN) ans2=min(ans2, (x+y-temp)<<1);
    		segupdate2(x, ps);
    		segupdate1(y, ps);
    	}
    }
    void trans() {
    	for(int i=1; i<=n; ++i) {
    		int x=p[i].x, y=p[i].y;
    		p[i].x=-y; p[i].y=x;
    	}
    }
    int ar[4][N][2];
    void work() {
    	for(int k=0; k<4; ++k) {
    		for(int i=1; i<=n; ++i) a[i]=p[i];
    		lisan();
    		if(k>=2) for(int i=2; i<=n; ++i) if(a[i].x==a[i-1].x && a[i].y==a[i-1].y) swap(a[i].id, a[i-1].id);
    		getans1(ar[k]);
    		getans2();
    		trans();
    	}
    	for(int i=1; i<=n; ++i) {
    		if(abs(ar[2][i][1])<MX && abs(ar[0][i][1])<MX) ans1=max(ans1, (-ar[2][i][1]-ar[0][i][1])<<1);
    		if(abs(ar[3][i][1])<MX && abs(ar[1][i][1])<MX) ans1=max(ans1, (-ar[3][i][1]-ar[1][i][1])<<1);
    		if(abs(ar[2][i][0])<MX && abs(ar[0][i][0])<MX) ans2=min(ans2, (-ar[2][i][0]-ar[0][i][0])<<1);
    		if(abs(ar[3][i][0])<MX && abs(ar[1][i][0])<MX) ans2=min(ans2, (-ar[3][i][0]-ar[1][i][0])<<1);
    	}
    }
    int main() {
    	seginit();
    	readin();
    	work();
    	printf("%d
    %d
    ", ans1, ans2);
    	return 0;
    }
  • 相关阅读:
    蓝桥杯 2014本科C++ B组 六角填数 枚举排列
    蓝桥杯 2014本科C++ B组 地宫取宝 DFS+记忆化搜索
    埃及分数 IDA*
    优先队列详解(转载)
    HDU 1242 Rescue BFS+优先队列
    HDU 1627 Krypton Factor
    2018中国机器人大赛服务机器人专项赛赛后总结
    OpenMP使用体验报告(概述)
    写在归程路上——2018ROBOCUP机器人世界杯中国赛
    ROS编译工作区缺少cv_bridge的问题解决
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4985750.html
Copyright © 2020-2023  润新知