TODO
时间复杂度 。
// 2023.05.27
#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9;
int n;
long long ans;
struct Point{
int x,y;
bool operator<(Point tmp)const{
if(x==tmp.x)return y<tmp.y;
else return x<tmp.x;
}
}a[100001];
struct Node{
int x,l,r;
}node[100001];
int cntNode;
map<long long,int> nodeId;
struct Edge{
int to,nxt;
}edge[200001];
int head[100001],cntEdge;
void addEdge(int u,int v){
edge[++cntEdge]={v,head[u]},head[u]=cntEdge;
edge[++cntEdge]={u,head[v]},head[v]=cntEdge;
}
int siz[100001];
void dfs(int id,int father){
siz[id]=node[id].r-node[id].l+1;
for(int i=head[id];i;i=edge[i].nxt)
if(edge[i].to!=father){
dfs(edge[i].to,id);
siz[id]+=siz[edge[i].to];
}
for(int i=head[id];i;i=edge[i].nxt)
if(edge[i].to!=father)
ans+=((long long)n-siz[edge[i].to])
*siz[edge[i].to]%mod,ans%=mod;
}
void calc(){
sort(a+1,a+1+n);
cntNode=cntEdge=0;
memset(head,0,sizeof head);
memset(edge,0,sizeof edge);
nodeId.clear();
for(int i=1;i<=n;i++)
if(i!=1&&a[i].x==a[i-1].x&&a[i].y==a[i-1].y+1)
node[cntNode].r=a[i].y,
nodeId[a[i].x*(long long)n+a[i].y]=cntNode;
else
node[++cntNode]={a[i].x,a[i].y,a[i].y},
nodeId[a[i].x*(long long)n+a[i].y]=cntNode;
for(int i=1;i<=cntNode;i++){
bool flag=false;
for(int j=node[i].l;j<=node[i].r;j++){
if(nodeId[(node[i].x+1)*(long long)n+j]){
if(!flag){
flag=true;
addEdge(i,nodeId[(node[i].x+1)*(long long)n+j]);
}
}
else flag=false;
}
}
dfs(1,0);
}
int main(){
scanf("%d",&n);
int minx=0x7fffffff,miny=0x7fffffff;
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y),
minx=min(minx,a[i].x),
miny=min(miny,a[i].y);
for(int i=1;i<=n;i++)
a[i].x-=minx-1,a[i].y-=miny-1;
calc();
for(int i=1;i<=n;i++)
swap(a[i].x,a[i].y);
calc();
printf("%lld\n",ans);
return 0;
}
本文作者是 hank0402,遵循 CC BY-NC-SA 4.0 协议。
考虑计算每条边对答案的贡献。
但如果直接建网格图,是没法直接 dp 的,难以解决,所以考虑转化为树上问题。
因为只有横边和竖边两种,并且统计方式类似,所以考虑将他们分开计数。
对于竖边,每一行的连续块对竖直距离的贡献是一样的,所以可以所成一点,大小为其包含的个数。
类似的建图后,我们发现形成了一棵树,至于为什么,可以考虑按行分割,行之间的点是没有连边的,并且有竖直的边当且仅当这一列两行间是连通的,若存在环一定会有白色被包围的现象。
接下来直接树形 dp,记录子树大小,对于每条边计算贡献即可。
复杂度为 。
void solve() {
memset(bel, 0, sizeof(bel));
memset(sz, 0, sizeof(sz));
for(int i = 1; i <= tot; ++i) S[i].clear();
for(int i = 1; i <= tot; ++i) seg[i].first = seg[i].second = xb[i] = 0;
for(int i = 1; i <= tot; ++i) ed[i].clear();
sort(p + 1, p + n + 1, cmp);
for(int i = 1; i <= n; ++i) {
chk[f(p[i].x, p[i].y)] = i;
}
tot = 1;
bel[1] = 1;
S[1].push_back(1);
xb[1] = p[1].x;
seg[1].first = seg[1].second = p[1].y;
for(int i = 2; i <= n; ++i) {
if(p[i].x == p[i - 1].x) {
if(p[i].y > p[i - 1].y + 1) {
bel[i] = ++tot;
S[tot].push_back(i);
seg[tot].first = seg[tot].second = p[i].y;
xb[tot] = p[i].x;
} else {
seg[tot].second = p[i].y;
bel[i] = tot;
S[tot].push_back(i);
}
} else {
++tot;
bel[i] = tot;
S[tot].push_back(i);
seg[tot].first = seg[tot].second = p[i].y;
xb[tot] = p[i].x;
}
}
for(int i = 1; i <= tot; ++i) {
for(int tmp = seg[i].first; tmp <= seg[i].second; ++tmp) {
if(bel[chk[f(xb[i] + 1, tmp)]] != 0) {
ed[i].push_back(bel[chk[f(xb[i] + 1, tmp)]]);
ed[bel[chk[f(xb[i] + 1, tmp)]]].push_back(i);
tmp = seg[bel[chk[f(xb[i] + 1, tmp)]]].second;
}
}
}
dfs(1, 0);
}