【CEOI2013】Adriatic

来源:互联网 发布:淘宝电脑客户端登陆 编辑:程序博客网 时间:2024/06/02 04:14

Description

“千岛之国”在20 世纪90 年代中期是克罗地亚旅游的官方宣传口号。虽然这个口号在技术上是不正确的(克罗地亚拥有略超过一千座岛屿),但是作为一个事实,环岛游(从一个岛航行到另一个岛)是一个流行的夏季活动。

为了这个任务的目标,亚得里亚海的地图被视为一个由正方形格子组成的、2500 行2500 列的网格。行号从1 到2500,从北到南编号;列从1 到2500,从西到东编号。海中有N 个岛屿,从1 到N 编号,并且各自都位于某个正方形单元格中。岛屿K 的位置通过给出所在格子的行号RK 和列号CK 获得。最后,没有两个岛在相同的格子内。

这里写图片描述

因为风和海流,所以从一个岛出发只可能到达大概西北方向或大概东南方向的岛屿。更确切地说,能从岛屿A 直接航行到岛屿B 仅当RA < RB 且CA < CB,或者RA > RB 且CA > CB。值得注意的是,能否从一个岛直接航行到另一个岛跟距离和他们之间其他岛屿没有关系。如果从A 不能直接到B,那么从A 出发经过几个中间岛屿是可能到达B 的。从A 到B 的航行距离定义为从A到B 的最小步数。

例如,在上图中,从行2 列3 的岛屿出发,能直接跳到4 个其他岛屿,然后到达剩下两个岛屿的航行距离均为二。

一个帆船代表大会正在计划中,并且组织者在考虑大会可能在哪个岛屿举行。当考虑某一个候选的岛屿,他们想知道:如果其他每个岛屿派出一条帆船,所有帆船到达候选岛屿的最小总步数是多少(等价于候选岛屿到所有岛屿航行距离的和)。写一个程序,使得若给出N 个岛屿的位置,对于每个岛屿K,计算出其他岛到K 的航行距离之和。

测试数据保证,对于任意的岛屿A 和岛屿B,均可直接互达或间接互达。

Input

输入的第一行包含一个整数N(3<=N<=250 000),岛屿数量。接下来的N 行包含岛屿位置。

对于每个位置,是一对1 到2500 之间的整数,分别为行号、列号。

Output

输出包含N 行。对于每个岛屿,以输入中的顺序,单独一行输出到其他岛屿航行距离之和。

Sample Input

输入1:

7

1 7

7 5

4 5

4 8

6 6

6 1

2 3

输入2:

4

1 1

2 3

3 2

4 4

Sample Output

输出1:

16

11

12

11

12

16

8

输出2:

3

4

4

3

Data Constraint

• 对于总值25points 的数据,N 最大100.

• 对于总值50points 的数据,N 最大1500.

• 对于总值60points 的数据,N 最大5000.

• 对于总值80points 的数据,N 最大25000.

题解

考虑dp
这一道题目有一个比较优的设状态的方法
对于一个点,它的左上和右下是可以一步到达的,而右上和左下是要多步的
考虑右上的情况
设g[i][j]表示除了(i-1,j-1)右上方的点到除这一片点之外的其他点,(假设为集合C)所需要的距离和
g[i][j]=sum1[i][j]+g[C中最上面的点的x][C中最右边的点的y]
然后做dfs就可以了
这样的话最后点对(x,y)的答案就是n+g1[x][y]+g2[x][y]-3,因为(x,y)被计算了3次
然后预处理一下四个“最”的前缀就好了

贴代码

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fo1(i,b,a) for(i=b;i>=a;i--)#define max(x,y) ((x)>(y)?(x):(y))#define min(x,y) ((x)<(y)?(x):(y))using namespace std;const int maxn=2505,maxq=250005;int g1[maxn][maxn],g2[maxn][maxn],sum1[maxn][maxn],sum2[maxn][maxn];int xia[maxn],sh[maxn],zo[maxn],yo[maxn];int q[maxq][3];int i,j,k,l,m,n,x,y,z;int read(){    int x=0; char ch=getchar();    while (ch<'0' || ch>'9') ch=getchar();    while (ch>='0' && ch<='9'){        x=x*10+ch-48;        ch=getchar();    }    return x;}int ge1(int x,int y){    if (g1[x][y]>=0) return g1[x][y];    if (sum1[x][y]<=1) return sum1[x][y];    g1[x][y]=sum1[x][y]+ge1(min(x,sh[y-1]),max(y,yo[x+1]));    return g1[x][y];}int ge2(int x,int y){    if (g2[x][y]>=0) return g2[x][y];    if (sum2[x][y]<=1) return sum2[x][y];    g2[x][y]=sum2[x][y]+ge2(max(x,xia[y+1]),min(y,zo[x-1]));    return g2[x][y];}int main(){//  freopen("t2.in","r",stdin);    n=read();    memset(zo,66,sizeof(zo)); zo[0]=6666;    memset(sh,77,sizeof(sh)); sh[0]=6666;    fo(i,1,n){        q[i][1]=read(); q[i][2]=read(); x=q[i][1]; y=q[i][2];        zo[x]=min(zo[x],y); yo[x]=max(yo[x],y);        sh[y]=min(sh[y],x); xia[y]=max(xia[y],x);        sum1[x][y]++; sum2[x][y]++;    }    fo(i,1,2500){        sh[i]=min(sh[i],sh[i-1]);        zo[i]=min(zo[i],zo[i-1]);    }    fo1(i,2500,1){        yo[i]=max(yo[i],yo[i+1]);        xia[i]=max(xia[i],xia[i+1]);    }    fo(i,1,2500)        fo1(j,2500,1){            sum1[i][j]=sum1[i][j]+sum1[i-1][j]+sum1[i][j+1]-sum1[i-1][j+1];        }    fo1(i,2500,1)        fo(j,1,2500){            sum2[i][j]=sum2[i][j]+sum2[i+1][j]+sum2[i][j-1]-sum2[i+1][j-1];        }    memset(g1,255,sizeof(g1));    memset(g2,255,sizeof(g2));    fo(i,1,n){        x=q[i][1]; y=q[i][2];        printf("%d\n",ge1(x,y)+ge2(x,y)+n-3);    }    return 0;}
原创粉丝点击