题意:

给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\n%d\n", ans1, ans2);
return 0;
}

【BZOJ】2675: Bomb的更多相关文章

  1. 【BZOJ】3052: [wc2013]糖果公园

    http://www.lydsy.com/JudgeOnline/problem.php?id=3052 题意:n个带颜色的点(m种),q次询问,每次询问x到y的路径上sum{w[次数]*v[颜色]} ...

  2. 【BZOJ】3319: 黑白树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种: ...

  3. 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...

  4. 【BZOJ】1013: [JSOI2008]球形空间产生器sphere

    [BZOJ]1013: [JSOI2008]球形空间产生器sphere 题意:给n+1个n维的点的坐标,要你求出一个到这n+1个点距离相等的点的坐标: 思路:高斯消元即第i个点和第i+1个点处理出一个 ...

  5. 【BZOJ】1002:轮状病毒(基尔霍夫矩阵【附公式推导】或打表)

    Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图 ...

  6. 【BZOJ】【3083】遥远的国度

    树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果roo ...

  7. 【BZOJ】【2434】【NOI2011】阿狸的打字机

    AC自动机+DFS序+BIT 好题啊……orz PoPoQQQ 大爷 一道相似的题目:[BZOJ][3172][TJOI2013]单词 那道题也是在fail树上数有多少个点,只不过这题是在x的fail ...

  8. 【BZOJ】【2738】&【Tsinsen】【A1333】矩阵乘法

    整体二分+树状数组 过了[BZOJ][2527][POI2011]Meteors以后这题就没那么难啦~ 关键是[从小到大]依次插入数字,然后整体二分每个查询的第k大是在第几次插入中被插入的……嗯大概就 ...

  9. 【BZOJ】【3170】【TJOI2103】松鼠聚会

    切比雪夫距离+曼哈顿距离 题解:http://www.cnblogs.com/zyfzyf/p/4105456.html 其实应该先做这题再做[BZOJ][3210]花神的浇花集会的吧…… 我们发现d ...

随机推荐

  1. Shell编程基础教程7--脚本参数的传递

    7.脚本参数的传递    7.1.shift命令        简介:            shift n        每次将参数位置向左偏移n位        例子 #!/bin/bash us ...

  2. 【openGL】四面体

  3. Fiddler Tips

    使用代理服务器 点击 Tools -> Fiddler Options -> Gateway Fiddler 默认将使用刚打开Fiddler窗口时IE 设置的代理服务器,当然你也可以手动修 ...

  4. iphone手机不同版本兼容、横竖屏

    /* 兼容问题*/ @media screen and (device-width: 320px) and (device-height: 480px) and (-webkit-device-pix ...

  5. hdu 4035 2011成都赛区网络赛E 概率dp ****

    太吊了,反正我不会 /* HDU 4035 dp求期望的题. 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点 ...

  6. 如何实现Outlook 2010 下载邮件后自动删除服务器上的邮件

    outlook2010---文件---信息---账户设置---选中要设置的帐号---双击点选要设置的邮箱---其他设置---高级---在服务器上保留邮件的副本---14天后删除服务器上的邮件副本,修改 ...

  7. APP设计尺寸规范大全,APP界面设计新手教程【官方版】(转)

    正值25学堂一周年之际,同时站长和APP设计同仁们在群里(APP界面设计 UI设计交流群,APP界面设计⑥群 APPUI设计③群58946771 APP设计资源⑤群 386032923欢迎大家加入交流 ...

  8. NSArray 所有基础点示例

    #import <Foundation/Foundation.h> //排序算法,应用于 NSArray *arr=[arrs1 sortedArrayUsingFunction:sort ...

  9. 使用postMesssage()实现跨域iframe页面间的信息传递----转载

    由于web同源策略的限制,当页面使用跨域iframe链接时,主页面与子页面是无法交互的,这对页面间的信息传递造成了不小的麻烦,经过一系列的尝试,最后我发现有以下方法可以实现: 1. 子页面url传参 ...

  10. yaml官方介绍

    官方网站 http://yaml.org/ 数据结构类型说明 http://yaml.org/type/ YAML Specification http://yaml.org/spec/