嘘~ 正在从服务器偷取页面 . . .

洛谷P6137 [IOI2012] 理想城 题解


洛谷P6137 [IOI2012] 理想城 题解

题目链接:P6137 [IOI2012] 理想城

题意

像许多同龄的科学家和艺术家一样,小 L 对城市规划和城区设计很感兴趣.他致力于构建一个理想城。理想城由 $N$ 个区块组成,而这些区块放在一个无限大的正方形网格上。第 $x$ 行第 $y$ 列的单元格由有序数对 $(x,y)$来标识。单元格 $(0,0)$ 位于网格的左上角。给定一个单元格 $(x,y)$,与之相邻的单元格(如果存在的话)分别为:$(x-1,y)$,$(x+1,y)$,$(x,y-1)$,$(x,y+1)$。每个区块在网格上恰好覆盖一个单元格。一个区块能够被放置在单元格 $(x,y)$ 上,当且仅当 $1 \le x,y \le 2^{31}-2$ 。我们将使用单元格的坐标同时来代表单元格上面的区块。若两个区块被放在相邻的单元格中,则视它们为相邻区块.理想城所有的区块连在一起,里面没有“洞”存在.换言之,所有单元格必须满足下述两个条件:

  • 对于任意两个空白的单元格,至少存在一连串相邻的空白单元格连接它们。
  • 对于任意两个非空的单元格,至少存在一连串相邻的非空单元格连接它们。

以下 $4$ 个图中的区块放置均不满足理想城的条件。前两个图不满足第一个条件。第 $3$ 个图不满足第二个条件,第 $4$ 个图两个条件均不满足。

当遍历理想城时,一个跳步代表从一个区块走到一个相邻的区块。跳步时不能移进空白单元格。假设 $v_0,v_1,\cdots,v_{N-1}$ 是 $N$ 个区块的坐标。对于任意两个不同的区块 $v_i$ 和 $v_j$,它们的距离 $d(v_i,v_j)$ 是从 $v_i$ 移动到 $v_j$ 所需的最小跳步数目。

下图是一个由 $11$ 个区块组成的理想城。区块坐标分别为

其中,$d(v_1,v_3)=1$,$d(v_1,v_8)=6$,$d(v_6,v_{10})=2$,$d(v_9,v_{10})=4$。

给定一个理想域,试求

输入格式

第 $1$ 行为一个正整数 $N$,为理想城区块的数目。

第 $2$ 行到第 $N+1$ 行,每行有两个非负整数。第 $i+2$ 行为第 $i$ 个区块的坐标 $v_i = (x_i, y_i)$。

输出格式

输出仅一行一个正整数,为 $S$ 的值。由于 $S$ 的值可能较大,你只需输出 $S$ 对 $10^9$ 取模的值。

数据范围

$1 \le N \le 10^5$,$1 \le x_i,y_i \le 2^{31}-2$ 。

讲一个非常简单的做法。考虑将横向和纵向的贡献分开计算。

这样对于四格方格的情况,即 $(i, j),(i+1, j),(i, j+1),(i+1, j+1)$ 均为理想城区划时

我们可以把 $(i,j)$ 和 $(i,j+1)$ 之间的边切掉,这样只考虑横向/纵向时这些区划就构成一棵树。

那么只需要暴力建树然后跑一遍 dfs 就能算出来了,一条边的贡献就是左右子树的大小之积。

时间复杂度 $\mathcal{O}(n \log n)$ ,因为连边需要用一下 map 。

代码:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
typedef pair<int,int> pii;
const int mod = 1e9; // wow!
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
void add(ll &x, ll y) { (x += y) >= mod ? x -= mod : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define pb push_back
#define Fi first
#define Se second
#define N ((int)(1e5 + 15))

int n, x[N], y[N], sz[N]; ll res;
map< int, map<int, int> >mp; vector<pii> vec[N];
void dfs(int u, int fa)
{
    sz[u] = 1;
    for(auto i : vec[u]) if(i.Fi != fa)
    {
        const int v = i.Fi, w = i.Se;
        dfs(v, u); sz[u] += sz[v];
        add(res, 1ll * sz[v] * (n - sz[v]) * w % mod);
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    rep(i, 1, n) cin >> x[i] >> y[i];
    for(int j = 0; j <= 1; dfs(1, 0), j++)
    {
        mp.clear(); rep(i, 1, n) vec[i].clear();
        rep(i, 1, n) { swap(x[i], y[i]); mp[x[i]][y[i]] = i; }
        rep(i, 1, n)
        {
            int t = mp[x[i] + 1][y[i]];
            if(t) { vec[t].pb({i, 0}); vec[i].pb({t, 0}); }
            t = mp[x[i]][y[i] + 1];
            if(t && !(mp[x[i] - 1][y[i]] && mp[x[i] - 1][y[i] + 1]))
                { vec[t].pb({i, 1}), vec[i].pb({t, 1}); }
        }
    }
    cout << res << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/un5u07gp


题外话

理想城计划!


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录