P6137 题解
daniEl_lElE · · 题解
考虑把贡献拆开,计算两个位置横向走的步数和纵向走的步数分别是多少。
考虑这样有什么好处,对于
这样断边以后,我们发现原图变为了树。于是我们只需要对于每个横向边记录左右两边的子树大小,乘积求和即可。
总复杂度
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9;
int x[100005],y[100005],siz[100005],ans,n;
map<pair<int,int>,int> mp;
vector<pair<int,int>> vc[100005];
void dfs(int now,int fa){
siz[now]=1;
for(auto v:vc[now]){
if(v.first==fa) continue;
dfs(v.first,now);
(ans+=siz[v.first]*(n-siz[v.first])*v.second)%=mod;
siz[now]+=siz[v.first];
}
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
}
for(int j=0;j<=1;j++){
mp.clear();
for(int i=1;i<=n;i++) vc[i].clear();
for(int i=1;i<=n;i++){
swap(x[i],y[i]);
mp[make_pair(x[i],y[i])]=i;
}
for(int i=1;i<=n;i++){
int v=mp[make_pair(x[i]+1,y[i])];
if(v){
vc[v].push_back(make_pair(i,0));
vc[i].push_back(make_pair(v,0));
}
v=mp[make_pair(x[i],y[i]+1)];
if(v){
if(!(mp[make_pair(x[i]-1,y[i])]&&mp[make_pair(x[i]-1,y[i]+1)])){
vc[v].push_back(make_pair(i,1));
vc[i].push_back(make_pair(v,1));
}
}
}
dfs(1,0);
}
cout<<ans;
return 0;
}