第1 行为一个正整数N,为理想城区块的数目。
第2 行到第N+1 行,每行有两个非负整数。第i+2 行为第i 个区块的坐标vi = (xi, yi)。node
输出仅一行一个正整数,为S 的值。因为S 的值可能较大,你只需输出S mod 10^9。web
11
2 5
2 6
3 3
3 6
4 3
4 4
4 5
4 6
5 3
5 4
5 6svg
这个作法很机智
由于图的特殊性质,若是将同一行连续的方格缩成一个点,上下相连的连边,必定可以构成一颗树
题目要求的是距离,那么先考虑两两点走过纵向的距离,横向的至关于把图翻转90°再求一次
先把图变成一棵树,树的每条边连的两个点就是原图中上下相邻的方格
那么这条边分开的两个部分中的方格的距离必定会通过这条边,也就是这条边的贡献是它两边的点的数量之积
完了,很简单是否是??spa
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 3123457
#define M 101000
#define ll long long
#define mo 1000000000ll
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
int last[M],next[M],to[M],tot=0,be[M];
ll ans=0,hs[N],bz[N],data[M],n,size[M];
int fx[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
struct node{
int x,y;
}p[M];
int hash(ll x)
{
int y=x%N;
while(1)
{
if(hs[y]==0||hs[y]==x) break;
y=(y+1)%N;
}
hs[y]=x;
return y;
}
void putin(int x,int y)
{
if(to[last[x]]==y) return;
next[++tot]=last[x];last[x]=tot;to[tot]=y;
}
bool cnt(node x,node y){return (x.x<y.x)||((x.x==y.x)&&(x.y>y.y));}
void INPUT()
{
scanf("%lld",&n);
int mi1=mo,mi2=mo;
fo(i,1,n)
{
scanf("%d%d",&p[i].x,&p[i].y);
mi1=min(mi1,p[i].x);mi2=min(mi2,p[i].y);
}
fo(i,1,n) p[i].x-=mi1-1,p[i].y-=mi2-1;
}
void RESET()
{
sort(p+1,p+n+1,cnt);
fo(i,1,n) bz[hash(p[i].x*n+p[i].y)]=i;
fd(i,n,1)
{
ll x=p[i].x,y=p[i].y;
if(be[i]==0)
{
be[i]=i;size[i]=1;
fd(j,i-1,1)
if(p[j].y==p[j+1].y+1) be[j]=i,size[i]++;else break;
}
int jy=hash((x+1)*n+y);
if(bz[jy]) putin(be[i],be[bz[jy]]),putin(be[bz[jy]],be[i]);
}
}
void dfs(int x,int fa)
{
for(int i=last[x];i;i=next[i])
{
int y=to[i];
if(y==fa) continue;
dfs(y,x);
size[x]+=size[y];
}
for(int i=last[x];i;i=next[i])
{
int y=to[i];
if(y==fa) continue;
ans=(ans+(size[y]*(n-size[y]))%mo)%mo;
}
}
int main()
{
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
INPUT();
RESET();
dfs(be[1],0);
fo(i,1,n) swap(p[i].x,p[i].y);
tot=0;
fo(i,1,M-1) last[i]=size[i]=be[i]=0;
fo(i,1,N-1) hs[i]=bz[i]=0;
RESET();
dfs(be[1],0);
printf("%lld",ans);
}