【BZOJ】2675: Bomb
题意:
给n个点,任选其中3个点(一个点只能取一次),求选出三个点的最大曼哈顿距离之和与最小曼哈顿距离之和(n<=10^5)。
题解:
最大曼哈顿距离之和很好求,就是能包围所有点的经过三个点的矩阵周长。
考虑最小曼哈顿距离之和。
我们考虑一个点,那么另外两个点会有两种分布。由于对称性,我们只考虑当前枚举的点在右上角、剩下两个点在左下角的情况。如果能求出这种情况的最优值,那么我们可以通过坐标系的旋转,使得剩下的情况也计算到了(这是做出本题的关键)。
可以发现曼哈顿距离就是包含三个点的最小矩形周长。
为了方便,我们假设每个点对应的坐标互不相同。(而实际中要考虑三个点或两个点有坐标相同的情况)
一、当剩下两个点其中一个点不在这个矩形上:
此时问题可以转化为,我们枚举中间这个点,然后统计
1、这个点与它的左下角和右上角
2、这个点与它的左上角和右下角
这两种情况的答案。
我们可以按y轴排序然后维护x轴的前缀最值求出一个方向的最值,然后通过坐标系的旋转求出每个方向的最值(注意实际中要讨论点重合的情况)
二、两个点都在矩阵上:
我们同样先y轴排序然后从小到大枚举。
假设右上角的点为1号点,剩下两个点为2、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的更多相关文章
- 【BZOJ】3052: [wc2013]糖果公园
http://www.lydsy.com/JudgeOnline/problem.php?id=3052 题意:n个带颜色的点(m种),q次询问,每次询问x到y的路径上sum{w[次数]*v[颜色]} ...
- 【BZOJ】3319: 黑白树
http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种: ...
- 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)
http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...
- 【BZOJ】1013: [JSOI2008]球形空间产生器sphere
[BZOJ]1013: [JSOI2008]球形空间产生器sphere 题意:给n+1个n维的点的坐标,要你求出一个到这n+1个点距离相等的点的坐标: 思路:高斯消元即第i个点和第i+1个点处理出一个 ...
- 【BZOJ】1002:轮状病毒(基尔霍夫矩阵【附公式推导】或打表)
Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图 ...
- 【BZOJ】【3083】遥远的国度
树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果roo ...
- 【BZOJ】【2434】【NOI2011】阿狸的打字机
AC自动机+DFS序+BIT 好题啊……orz PoPoQQQ 大爷 一道相似的题目:[BZOJ][3172][TJOI2013]单词 那道题也是在fail树上数有多少个点,只不过这题是在x的fail ...
- 【BZOJ】【2738】&【Tsinsen】【A1333】矩阵乘法
整体二分+树状数组 过了[BZOJ][2527][POI2011]Meteors以后这题就没那么难啦~ 关键是[从小到大]依次插入数字,然后整体二分每个查询的第k大是在第几次插入中被插入的……嗯大概就 ...
- 【BZOJ】【3170】【TJOI2103】松鼠聚会
切比雪夫距离+曼哈顿距离 题解:http://www.cnblogs.com/zyfzyf/p/4105456.html 其实应该先做这题再做[BZOJ][3210]花神的浇花集会的吧…… 我们发现d ...
随机推荐
- Python 小游戏 Bunny
最近在学习Python,所以上网找了一个小程序练练手. 关于这款名为[Bunny]的小游戏,详细请看下面的链接: http://www.oschina.net/translate/beginning- ...
- Log4Net配置以及使用
跟踪程序代码,及时发现程序的运行状态,是每个成熟的软件所必不可少的一个环节,网站发布到真实的环境之后,对于程序的运行状态,我们并不能想开发环境那也,点击调试.日志记录显示就尤为重要,在.NET中记录日 ...
- shell test 數值 字符串 文件比較
數值比較 描述 n1 –eq n2 等於 n1 –gt n2 大於 n1 –ge n2 大於等於 n1 –lt n2 小於 n1 –le n2 小於等於 n1 –ne n2 不等於 字符串比較 ...
- android 入门-git之上传本地代码到github
github部分: 1.首先去github网站 上注册一个用户 2.说明 https://guides.github.com/activities/hello-world/ 2.点击 New repo ...
- Java中的异或(转)
在java程序里面的异或用法: 相同输出0,不同输出1,例如: System.out.println(1^1); 输出0 System.out.println(1^2):输出3,因为最后2个低位都不一 ...
- loj 1337
题目链接:http://lightoj.com/volume_showproblem.php?problem=1337 思路:对于搜过的区域进行标记,如果要求的点落在已经搜过的区域,那么直接取出来即可 ...
- 使用MulticastSocket实现多点广播
原文链接:http://hbiao68.iteye.com/blog/1943354 使用MulticastSocket实现多点广播 DatagramSocket只允许数据报发送给指定的目标地址,而M ...
- 通信原理实践(五)——2PSK 与2DPSK 通信系统
一.一些Matlab函数 二.2PSK调制解调,性能分析 1.2PSK调制 (1)图示 (2)Matlab代码 function [ s_t ,bb_t,bits] = psk2_module( nS ...
- Hibernate 延迟加载
一.什么是延迟加载? 延迟加载是指当应用程序想要从数据库获取对象时(在没有设置lazy属性值为false),Hibernate只是从数据库获取符合条件的对象的OId从而生成代理对象,并没有加载出对象访 ...
- 转载 linux内核 asmlinkage宏
转载http://blog.chinaunix.net/uid-7390305-id-2057287.html 看一下/usr/include/asm/linkage.h里面的定义:#define a ...