当前位置: 首页 > news >正文

jzoj2866. 【集训队互测 2012】Bomb

Description

A 国和 B 国是两个超级大国,长期处于冷战状态;
A 国在 B 国中设有 N 个情报站,编号为 1,2,3, …… ,N ,每个情报站有一个坐标 (Xi,Yi) 。但是, A 国的工作人员发现,每个情报站里都被埋上了炸弹!
这些炸弹非常特殊 , 只要同时拆除其中的三个炸弹 , 所有炸弹就都不会爆炸了。
由于各个情报站联络需要代价 , 拆除炸弹需要花费的总代价为这些炸弹两两之间的曼哈顿距离和。
现在 A 国的指挥部门找到了你 , 希望知道可能需要的最大代价和最小代价 。

Input

输入的第一行包含一个整数 N 。接下来 N 行,第 i+1 行两个整数 Xi,Yi ,表示第 i 个情报站的坐标。

Output

输出两行 , 每行包含一个整数 , 第一行表示可能的最大代价 , 第二行表示可能的最小代价。

Sample Input

4
1 1
1 2
2 1
2 3

Sample Output

6
4

Data Constraint

对于 30% 的数据, N<=500
对于另外 10% 的数据,每个点出现至少两遍
对于 50% 的数据, N<=1000
对于 60% 的数据, N<=8000
对于 70% 的数据, N<=15000
对于 80% 的数据, N<=50000
对于 100% 的数据, N<=100000 , 0<=Xi,Yi<=10^8

Hint

对于两个点 (X0,Y0),(X1,Y1) ,
它们之间的曼哈顿距离为 abs(X0-X1)+abs(Y0-Y1) 。

赛时

这道题比较奇妙。
一开始我还以为是什么计算几何神仙题。
结果推一推发现不是。
无脑选手++
最后交了个30分暴力滚粗。

题解

话说这道题数据有点水,可以利用\(n^2\)卡到90分。
然后利用分段打表两者相结合就过了。
无话可说

100%
我们首先考虑最大值怎么求:
我们发现,一个点对答案做出贡当且仅当其作为Xmin,Xmax,Ymin,Ymax出现才行。
然后贪心做即可。

然后就是最小值怎么求:
我们首先把整个图形旋转90旋转4次,每次就会出现以下两种情况可能对答案有贡献:
在这里插入图片描述
在这里插入图片描述
对于第一种,我们直接枚举中间的点,然后找出其右上方向离它最近的点,和左下方向离它最近的点。
更新答案即可。
但是一定要注意到重复出现的点。

对于第二种,做法就比较神奇了。
我们看到上图,可以发现,最左下的点提供Xmin,Ymin
最上面的点提供Ymax,最右边的点提供Xmax。
那么我们只需要快速求出后面两个即可。

考虑扫描线,首先当然是离散化y轴啦~
我们考虑从右往左边扫。
在这个y轴建立一个线段树,线段树上每个点记录的是:
x:当前行到扫到的列最近的点的x坐标。
y:在当前行上距离当前行最近的点的y坐标。
ans:当前点作为最右边的点的答案。
那么每次扫到一个点(xi,yi),我们就在线段树上求出它上面的点中答案最小的点。
然后更新。
首先,把当前点所在的行的x更新成xi
然后把当前点下面的行的y都打上lazy标记。
每次下传标记时我们就判断lazy标记是否能更新y值(lazy<y)同时更新ans即可。
实现起来细节还是比较多的(尤其是标记下传)

标程

小细节真™多。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

struct node
{
    long long xmin,ymin,ans;
};

int n;
long long maxans,minans,ans,pp;
long long x[100010],y[100010],ny[100010],id[100010];
long long lazy[400010],t[400010],op[100010][5],gb[400010],xx[100010],yy[100010];
node tree[400010],gbt[400010];

int abs(int x)
{
    if (x<0) return -x;
    else return x;
}

void qsort(int l,int r)
{
    int i=l;int j=r;
    int m=xx[(i+j)/2];
    int m1=yy[(i+j)/2];
    int m2=id[(i+j)/2];
    while (i<=j)
    {
        while ((xx[i]>m)||(xx[i]==m && yy[i]>m1)||(xx[i]==m && yy[i]==m1 && ((pp==0 && id[i]>m2)||(pp==1 && id[i]<m2)))) i++;
        while ((xx[j]<m)||(xx[j]==m && yy[j]<m1)||(xx[j]==m && yy[j]==m1 && ((pp==0 && id[j]<m2)||(pp==1 && id[j]>m2)))) j--;
        if (i<=j)
        {
            swap(xx[i],xx[j]);
            swap(yy[i],yy[j]);
            swap(ny[i],ny[j]);
            swap(id[i],id[j]);
            i++;j--;
        }
    }
    if (l<j) qsort(l,j);
    if (r>i) qsort(i,r); 
}

void qsorty(int l,int r)
{
    int i=l;int j=r;
    int m=yy[(i+j)/2];
    while (i<=j)
    {
        while (yy[i]<m) i++;
        while (yy[j]>m) j--;
        if (i<=j)
        {
            swap(yy[i],yy[j]);
            swap(xx[i],xx[j]);
            swap(id[i],id[j]);
            i++;j--;
        }
    }
    if (l<j) qsorty(l,j);
    if (r>i) qsorty(i,r); 
}

void lazy_down(int x)
{
    tree[x*2].ymin=min(tree[x*2].ymin,lazy[x]);
    tree[x*2+1].ymin=min(tree[x*2+1].ymin,lazy[x]);
    lazy[x*2]=min(lazy[x*2],lazy[x]);
    lazy[x*2+1]=min(lazy[x*2+1],lazy[x]);
    tree[x*2].ans=min(tree[x*2].ans,tree[x*2].xmin+lazy[x]); 
    tree[x*2+1].ans=min(tree[x*2+1].ans,tree[x*2+1].xmin+lazy[x]);
    lazy[x]=1000000000;
}

void queryall(int x,int l,int r,int st,int en)
{
    if (l==st && r==en)
    {
        ans=min(ans,tree[x].ans);
    }
    else
    {
        int mid=(l+r)/2;
        lazy_down(x);
        if (en<=mid) queryall(2*x,l,mid,st,en);
        else if (st>mid) queryall(2*x+1,mid+1,r,st,en);
        else
        {
            queryall(2*x,l,mid,st,mid);
            queryall(2*x+1,mid+1,r,mid+1,en);
        }       
    }
}

void find(int x,int l,int r,int st,int en)
{
    if (l==st && r==en)
    {
        ans=min(ans,t[x]);
    }
    else
    {
        int mid=(l+r)/2;
        if (en<=mid) find(2*x,l,mid,st,en);
        else if (st>mid) find(2*x+1,mid+1,r,st,en);
        else
        {
            find(2*x,l,mid,st,mid);
            find(2*x+1,mid+1,r,mid+1,en);
        }       
    }
}

void change(int x,int l,int r,int st,int en)
{
    if (l==r)
    {
        t[x]=en;
    }
    else
    {
        int mid=(l+r)/2;
        if (st<=mid) change(2*x,l,mid,st,en);
        else if (st>mid) change(2*x+1,mid+1,r,st,en);   
        t[x]=min(t[2*x],t[2*x+1]);
    }
}

void modifyx(int x,int l,int r,int st,int en)
{
    if (l==r)
    {
        tree[x].xmin=en;
    }
    else
    {
        int mid=(l+r)/2;
        lazy_down(x);
        if (st<=mid) modifyx(2*x,l,mid,st,en);
        else if (st>mid) modifyx(2*x+1,mid+1,r,st,en);  
        tree[x].xmin=min(tree[2*x].xmin,tree[2*x+1].xmin);
    }
}

void modifyy(int x,int l,int r,int st,int en,long long op)
{
    if (l==st && r==en)
    {
        if (tree[x].ymin>op)
        {
            tree[x].ymin=op;
        }       
        lazy[x]=min(lazy[x],op);
        tree[x].ans=min(tree[x].ans,tree[x].xmin+op);
    }
    else
    {
        int mid=(l+r)/2;
        lazy_down(x);
        if (en<=mid) modifyy(2*x,l,mid,st,en,op);
        else if (st>mid) modifyy(2*x+1,mid+1,r,st,en,op);
        else
        {
            modifyy(2*x,l,mid,st,mid,op);
            modifyy(2*x+1,mid+1,r,mid+1,en,op);
        }   
        tree[x].ymin=min(tree[2*x].ymin,tree[2*x+1].ymin);
        tree[x].ans=min(tree[2*x].ans,tree[2*x+1].ans); 
    }
}

void find_min(int now)
{
    for (int i=1;i<=n;i++)
    {
        id[i]=i;
    }
    qsorty(1,n);
    int j=1;
    ny[1]=1;
    for (int i=2;i<=n;i++)
    {
        if (yy[i]!=yy[i-1])
        {
            j++;
        }
        ny[i]=j;
    }
    int zd=j;
    qsort(1,n);
    memcpy(tree,gbt,sizeof(gbt));
    memcpy(lazy,gb,sizeof(gb));
    memcpy(t,gb,sizeof(gb));
    for (int i=1;i<=n;i++)
    {
        ans=1000000000;
        find(1,1,zd,ny[i],zd);
        op[id[i]][now]=min(op[id[i]][now],ans-xx[i]-yy[i]);
        change(1,1,zd,ny[i],xx[i]+yy[i]);
        ans=1000000000;
        if (i>=3)
        if (ny[i]<zd)
        queryall(1,1,zd,ny[i]+1,zd);
        minans=min(minans,ans-xx[i]-yy[i]);
        modifyx(1,1,zd,ny[i],xx[i]);
        if (ny[i]>1)
        modifyy(1,1,zd,1,ny[i]-1,yy[i]);
    }
}

void find_max()
{
    long long xmin=1000000000;
    long long ymin=1000000000;
    long long xmax=-1000000000;
    long long ymax=-1000000000;
    for (int i=1;i<=n;i++)
    {
        xmin=min(xmin,xx[i]);
        xmax=max(xmax,xx[i]);
        ymin=min(ymin,yy[i]);
        ymax=max(ymax,yy[i]);
    }
    for (int i=1;i<=n;i++)
    {
        maxans=max(maxans,2*(max(xx[i]-xmin,xmax-xx[i])+max(yy[i]-ymin,ymax-yy[i])));
    }
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
    }
    maxans=-1000000000;
    minans=1000000000;
    for (int i=0;i<400000;i++) gb[i]=1000000000;
    for (int i=0;i<400000;i++)
    {
        gbt[i].ans=1000000000;
        gbt[i].xmin=1000000000;
        gbt[i].ymin=1000000000;
    }
    memset(op,127,sizeof(op));
    memcpy(xx,x,sizeof(x));
    memcpy(yy,y,sizeof(y));
    find_max();
    for (int i=1;i<=4;i++)
    {
        memcpy(xx,x,sizeof(x));
        memcpy(yy,y,sizeof(y));
        if (i==1) find_min(i);
        else if (i==2)
        {
            for (int j=1;j<=n;j++)
            {
                swap(xx[j],yy[j]);
                yy[j]+=100000000;
                xx[j]=100000000-xx[j];
            }
            find_min(i);
        }
        else
        if (i==3)
        {
            pp++;
            for (int j=1;j<=n;j++)
            {
                xx[j]=6-xx[j];
                yy[j]=6-yy[j];
            }
            find_min(i);
        }
        else
        {
            for (int j=1;j<=n;j++)
            {
                swap(xx[j],yy[j]);
                yy[j]=100000000-yy[j];
                xx[j]+=100000000;
            }
            find_min(i);
        }
    }
    for (int i=1;i<=n;i++)
    {
        minans=min(minans,op[i][1]+op[i][3]);
        minans=min(minans,op[i][2]+op[i][4]);
    }
    printf("%d\n",maxans);
    printf("%d\n",minans*2);
}

转载于:https://www.cnblogs.com/RainbowCrown/p/11294112.html

相关文章:

  • python自动化运维技术读书笔记
  • js同步和异步
  • 并发并行同步异步多线程
  • 猿辅导 2019年 校招提前批笔试
  • RequireJs入门
  • Asp.net页面的生命周期
  • 终于弄好了 homework-09
  • python面向对象
  • leetcode 337. House Robber III
  • Durandal入门
  • js中使用EL表达式总结
  • leetcode 309. Best Time to Buy and Sell Stock with Cooldown
  • 环境变量
  • 手机端和网页端使用同一后台时进行会话控制
  • SpringBoot起步
  • C学习-枚举(九)
  • java8 Stream Pipelines 浅析
  • MySQL用户中的%到底包不包括localhost?
  • 简单数学运算程序(不定期更新)
  • 开源地图数据可视化库——mapnik
  • 跨域
  • 微信小程序:实现悬浮返回和分享按钮
  • 正则表达式
  • Java总结 - String - 这篇请使劲喷我
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 如何正确理解,内页权重高于首页?
  • 昨天1024程序员节,我故意写了个死循环~
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • #etcd#安装时出错
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • (搬运以学习)flask 上下文的实现
  • (二)WCF的Binding模型
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (一)Java算法:二分查找
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转载)hibernate缓存
  • .NET delegate 委托 、 Event 事件,接口回调
  • .Net 高效开发之不可错过的实用工具
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET/C# 使窗口永不获得焦点
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [20170713] 无法访问SQL Server
  • [BZOJ 3531][Sdoi2014]旅行(树链剖分+线段树)
  • [C#][DevPress]事件委托的使用
  • [CISCN2019 华东北赛区]Web2
  • [codeforces]Recover the String
  • [ERROR] Plugin 'InnoDB' init function returned error
  • [Java][算法 双指针]Day 02---LeetCode 热题 100---04~07
  • [leetcode] Balanced Binary Tree
  • [LeetCode]Max Points on a Line
  • [leetcode]Symmetric Tree