正题
题目大意
一个理想城市有nnn个块构成,有以下性质
- 任意两个块之间可以通过其他块到达
- 任意两个块之间可以不通过其他块(通过空位)到达
然后求每个块之间的距离之和。
解题思路
我们将横竖的距离分开计算。
假设现在我们考虑计算竖向的边的距离,我们将横向的连续的块缩成一个点(如下图)
然后将相邻的两个块连边,这样,因为上面的性质那么就能够保证这样是一个树形结构。然后计算每条边对应这些数对来说总共被走了多少次。也就是对于每条x−>yx->yx−>y的边,那么有(n−sizey)∗sizey(n-size_y)*size_y(n−sizey)∗sizey这么多个点对走过这条边
然后横着计算一次竖着计算一次将答案加和即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define p(x,y) ((x)*n+(y))
#define ll long long
using namespace std;
const ll N=100100,XJQ=1e9,M=3123656;
struct node{ll x,y;
}w[N];
struct edge_node{ll to,next;
}a[M*2];
map<int,int> bz;
ll n,bx,mx,cnt,size[M],ls[M],tot,by,be[M];
long long ans;
bool cmp(node x,node y)
{return x.x==y.x?x.y>y.y:x.x<y.x;}
void adde(ll x,ll y)
{if(a[ls[x]].to==y) return;a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dp(ll x,ll fa)
{for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa) continue;dp(y,x);size[x]+=size[y];}for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa) continue;ans=(ans+(long long)(size[y]*(n-size[y]))%XJQ)%XJQ;}
}
void Reset()
{sort(w+1,w+1+n,cmp);for(ll i=1;i<=n;i++)bz[p(w[i].x,w[i].y)]=i;for(ll i=n;i>=1;i--){ll x=w[i].x,y=w[i].y;if(be[i]==0){be[i]=i;size[i]=1;for(ll j=i-1;j>=1;j--)if(w[j].y==w[j+1].y+1) be[j]=i,size[i]++;else break;}ll k=bz[p(x+1,y)];if(k)adde(be[k],be[i]),adde(be[i],be[k]);}
}
int main()
{freopen("city.in","r",stdin);freopen("city.out","w",stdout);scanf("%lld",&n);bx=2147483647;by=2147483647;for(ll i=1;i<=n;i++)scanf("%lld%lld",&w[i].x,&w[i].y),bx=min(bx,w[i].x),by=min(by,w[i].y);for(ll i=1;i<=n;i++)w[i].x-=bx-1,w[i].y-=by-1;Reset();dp(be[1],0);swap(bx,by);for(ll i=1;i<=n;i++)swap(w[i].x,w[i].y);tot=0;memset(ls,0,sizeof(ls));memset(be,0,sizeof(be));memset(size,0,sizeof(size));bz.clear();Reset();dp(be[1],0);printf("%lld",ans);
}