题目:
题意:
给出一个没有洞的理想城市,设
d
(
i
,
j
)
d(i,j)
d(i,j)表示
i
i
i到
j
j
j的最短距离
求最小的
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
d
(
i
,
j
)
\sum_{i=1}^{n-1}\sum_{j=i+1}^nd(i,j)
∑i=1n−1∑j=i+1nd(i,j)
分析:
将同一行连在一起的点都缩成一个连通块,然后将同列相邻的节点连边,那么最终出来的必定会是一棵树
我们用
s
i
z
e
i
size_i
sizei表示以
i
i
i为根的子树的大小是多少,那么就能用一个简单的
d
p
dp
dp得出
1
—
n
1—n
1—n的所有答案:
s
i
z
e
i
+
=
s
i
z
e
v
(
v
为
i
的
子
节
点
)
size_i+=size_v(v为i的子节点)
sizei+=sizev(v为i的子节点)
这样之后我们再来思考怎么得到最终的答案
先来康康这张图
当红点转移到紫点时,所有绿点的答案都会
+
1
+1
+1,而所有蓝点的答案都会
−
1
-1
−1
在结合到树上,对于每条边,所有绿点和蓝点都会经过一次,我们就有了一个公式:
a
n
s
+
=
s
i
z
e
[
i
]
∗
(
n
−
s
i
z
e
[
i
]
)
ans+=size[i]*(n-size[i])
ans+=size[i]∗(n−size[i])
当前的情况是横着缩的,对于竖着缩的也是同理
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#define LZX 1000000000
#define mar 3123457
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
struct qwq{
LL x,y;
}t[100005];
LL h[3123460];
LL hash(LL x)
{
LL y=x%mar;
while(1)
{
if(!h[y]||h[y]==x) break;
y=(y+1)%mar;
}
h[y]=x;
return y;
}
bool cmp(qwq x,qwq y) {if(x.x==y.x) return x.y>y.y; else return x.x<y.x;}
LL nu[3123460],fa[100005],size[100005];
struct node{
LL to,next;
}e[200005];
LL cnt=0,ls[200005];
void add(LL x,LL y)
{
if(e[ls[x]].to==y) return;
e[cnt]=(node){y,ls[x]};
ls[x]=cnt++;
return;
}
LL ans=0,n;
void dfs(LL k,LL f)
{
for(LL i=ls[k];~i;i=e[i].next)
{
LL v=e[i].to;
if(v==f) continue;
dfs(v,k);
size[k]+=size[v];
}
for(LL i=ls[k];~i;i=e[i].next)
{
LL v=e[i].to;
if(v==f) continue;
(ans+=size[v]*(n-size[v])%LZX)%=LZX;
}
return;
}
void st()
{
sort(t+1,t+1+n,cmp);
for(LL i=1;i<=n;i++) nu[hash(t[i].x*n+t[i].y)]=i;
for(LL i=n;i;i--)
{
LL x=t[i].x,y=t[i].y;
if(!fa[i])
{
fa[i]=i;size[i]=1;
for(LL j=i-1;j;j--)
if(t[j].y==t[j+1].y+1) fa[j]=i,size[i]++;
else break;
}
LL xl=hash((x+1)*n+y);
if(nu[xl]) add(fa[i],fa[nu[xl]]),add(fa[nu[xl]],fa[i]);
}
return;
}
int main()
{
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
memset(ls,-1,sizeof(ls));
n=read();LL minx=2147483647,miny=2147483647;
for(LL i=1;i<=n;i++) t[i].x=read(),t[i].y=read(),minx=min(minx,t[i].x),miny=min(miny,t[i].y);
for(LL i=1;i<=n;i++) t[i].x-=minx-1,t[i].y-=miny-1;
st();
dfs(fa[1],0);
for(LL i=1;i<=n;i++) swap(t[i].x,t[i].y);
memset(ls,-1,sizeof(ls));memset(fa,0,sizeof(fa));memset(size,0,sizeof(size));memset(nu,0,sizeof(nu));memset(h,0,sizeof(h));
st();
dfs(fa[1],0);
cout<<ans;
return 0;
}