【JZOJ3738】理想城市(city)

Description

这里写图片描述

Solution

把求的答案变一下,相当于一个非空的格可以往下走,答案就要加上经过这一步的路径总数。

那么,我们把横着连在一起的非空格缩成一个点(连通块),如果两个点上下有接触,就给两个点连边。这样构建的图一定是一棵树,那么我们考虑一条树边的贡献,就是它的两个端点分别连出去的点包含着非空格子数相乘。

竖着的同理。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define N 100010
#define M 200010
#define mod 3000007
#define ll long long
#define inf 2147483647
#define mo 1000000000
using namespace std;
struct node{
    int x,y;
}b[N];
int to[M],nx[M],ls[N],num=0;
void link(int x,int y){
    to[++num]=y,nx[num]=ls[x],ls[x]=num;
}
ll h[mod];
int r=0,c=0;
int o[mod];
int g(int x,int y){
    return (ll)(x-1)*c+y;
}
int f[N],fc[N],sz[N];
int n;
ll ans=0;
int getf(int x){
    return f[x]==x?x:f[x]=getf(f[x]);
}
int getfc(int x){
    return fc[x]==x?x:fc[x]=getfc(fc[x]);
}
int hash(ll x)
{
    int p=x%mod;
    while(h[p] && h[p]!=x) p=(p+1)%mod;
    return p;
}
void calc(int x,int t)
{
    rep(i,x)
    {
        int v=to[i];
        if(v==t) continue;
        calc(v,x);
        sz[x]+=sz[v];
    }
    rep(i,x)
    {
        int v=to[i];
        if(v==t) continue;
        ans=(ans+(ll)sz[v]*(n-sz[v]))%mo;
    }
}
void work(int v1,int v2)
{
    memset(ls,0,sizeof(ls));
    num=0;
    fo(i,1,n) f[i]=fc[i]=i,sz[i]=1;
    fo(i,1,n)
    {
        int x=b[i].x,y=b[i].y;
        if(x+v1>r || y+v2>c) continue;
        int w1=hash(g(x,y)),w2=hash(g(x+v1,y+v2));
        if(h[w2])
        {
            int fx=getf(o[w1]),fy=getf(o[w2]);
            f[fy]=fx,sz[fx]+=sz[fy];
            sz[fy]=0;
        }
    }
    fo(i,1,n)
    {
        int x=b[i].x,y=b[i].y;
        if(x+v2>r || y+v1>c) continue;
        int w1=hash(g(x,y)),w2=hash(g(x+v2,y+v1));
        if(h[w2])
        {
            int fx=getf(o[w1]),fy=getf(o[w2]);
            int gx=getfc(fx),gy=getfc(fy);
            if(gx!=gy) fc[gy]=gx,link(fx,fy),link(fy,fx);
        }
    }
    calc(getf(1),0);
}
int main()
{
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);
    scanf("%d",&n);
    int p=inf,q=inf;
    fo(i,1,n)
    {
        scanf("%d %d",&b[i].x,&b[i].y);
        p=min(p,b[i].x),q=min(q,b[i].y);
        r=max(r,b[i].x),c=max(c,b[i].y);
    }
    p--,q--;
    r-=p,c-=q;
    fo(i,1,n)
    {
        b[i].x-=p,b[i].y-=q;
        ll t=g(b[i].x,b[i].y);
        int wz=hash(t);
        o[wz]=i,h[wz]=t;
    }
    work(0,1);
    work(1,0);
    printf("%lld",ans);
}
posted @ 2017-03-22 20:38  sadstone  阅读(46)  评论(0编辑  收藏  举报