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

CF1527D MEX Tree 题解


CF1527D MEX Tree 题解

题目链接:CF1527D MEX Tree

题意

本题有多组测试数据。

给出一棵 \(n\) 个点的树,点从 \(0\)\(n - 1\) 编号。定义一条路径的权值是路径上所有点编号的 \(\operatorname{mex}\)。对于每个 \(0\le i\le n\) 求出 \(\operatorname{mex}\)\(i\) 的路径有几条。注意,这里统计的路径需要包括至少一条边。

一个集合的 \(\operatorname{mex}\) 定义为最小的不在集合中的非负整数。

数据范围

\(2 \le n \le 2\times 10^5, \sum n_i \le 2\times 10^5\)

先考虑在链上怎么做。我们从 \(0\) 开始往上推,设当前枚举到了 \(x\)

可以发现 \(0\)\(x\) 的数一定会在一个区间 \([l,r]\) 内,根据乘法原理可知 \(\mathrm{mex} > x\) 的路径数有 \(l\times (n - r + 1)\) 条。

接着考虑在树上怎么做。显然,到了树上,\(0\)\(x\) 就很难在同一条链上了。

不过我们注意到,如果 \(0\)\(x\) 不在一条链上,那么能通过这些数的路径也不存在。

否则一定可以用一条链连接 \(0\)\(x\) ,于是我们可以维护这条链和链两端的节点数。

具体地,如果当前点不在链上,就不停跳 fa 直到找到已经在链上的点。

如果这个点是端点,那么更新端点,否则一定不是一条链。

时间复杂度 \(\mathcal{O}(n\log n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5 + 15))

vector<int> T[N];
int n,ans,m,l,r,L,R,a[N],b[N],sz1[N],sz2[N],fa[N],S[N];
void dfs(int u, int f, int sz[])
{
    fa[u] = f; sz[u] = 1;
    for(int v : T[u]) if(v != f) { dfs(v, u, sz); sz[u] += sz[v]; }
}
void solve()
{
    cin >> n;
    for(int i = 0; i <= n; i++) T[i].clear();
    for(int i = 1, x,y; i < n; i++)
    {
        cin >> x >> y;
        T[x].push_back(y); T[y].push_back(x);
    }
    for(int i = 0; i <= n + 1; i++) { a[i] = sz1[i] = sz2[i] = S[i] = 0; }
    l = r = 0; dfs(0, -1, sz1); a[0] = n * (n - 1) / 2; a[1] = 2 * n - 2;
    for(int v : T[0]) a[1] += (n - 1 - sz1[v]) * sz1[v];
    a[1] /= 2; dfs(1, -1, sz2); l = 1, r = 0; L = sz1[l]; R = sz2[r]; a[2] = L * R;
    int x = 0; while(x != 1) S[x] = 1, x = fa[x]; S[1] = 1;
    for(int k = 2; k < n; k++)
    {
        if(S[k]) { a[k + 1] = L * R; continue; }
        int t = k; while(!S[t]) t = fa[t];
        if(t == l)
        {
            int x = k; while(x != l) { S[x] = 1, x = fa[x]; }
            l = k, L = sz1[l], a[k + 1] = L * R;
        } else if(t == r)
        {
            int x = k; while(x != r) { S[x] = 1, x = fa[x]; }
            r = k, R = sz2[r], a[k + 1] = L * R;
        }else break;
    }
    for(int i = 0; i <= n; i++) { a[i] -= a[i + 1], cout << a[i] << " \n"[i == n]; }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int qwq; cin >> qwq; while(qwq--) solve(); // Great!
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/LilliaAsupurei/solution-cf1527d


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