1 条题解

  • 0
    @ 2026-9-23 22:16:43

    下面记 a∈Aa \in A,b∈Bb \in B。

    考虑 aa 和 bb 怎么走最优。

    下面说的平局为 aa 不能再走一步的同时,bb 也不能再走了。

    当 aa 走一步时,能压缩 bb 所能走的空间,这是优的,顺着想下去就能发现当 aa 和 bb 相邻时,双方都只能走自己子树内的节点,所以 aa 和 bb 会以简单路径的方式靠近对方,当不会出现平局且两节点相邻,其中一定有一个点的子树大小超过 ⌊n2⌋\lfloor \frac{n}{2} \rfloor 时,那么这个点就赢了。想到树的重心的性质,删掉重心后,连通块的大小大于 ⌊n2⌋\lfloor \frac{n}{2} \rfloor。这里需要讨论树的重心的个数。 ::::info[有一个时] 以这个点为根,记 dud_u 为 uu 节点的深度,一个 aa 所能产生的贡献就是 ∑b∈B[da≤db]\sum_{b \in B} [d_{a} \le d_b],这个用树状数组维护。 :::: ::::info[有两个时] 在只有一个树的重心所能产生的贡献是误加上的,当 aa 和 bb 不属于同一个重心且到各自的重心距离相同时会产生平局,所以需要把这种情况减掉。 ::::

    #include<bits/stdc++.h>
    const int MAXN = 500000 + 5;
    #define pb push_back
    typedef long long LL;
    int n, sa, sb, q, a[MAXN], b[MAXN];
    std::vector<int> e[MAXN];
    inline void add(int u, int v)
    {
        e[u].pb(v);
    }
    int rt[3], ps, sz[MAXN];
    inline void dfs(int u, int fa)
    {
        sz[u] = 1;
        bool fl = 1;
        for(int v : e[u])
        {
            if(!(v ^ fa))
                continue;
            dfs(v, u);
            sz[u] += sz[v];
            if(sz[v] > n / 2)
                fl = 0;
        }
        if(n - sz[u] > n / 2) fl = 0;
        if(fl) rt[++ps] = u;
    }
    int depth[MAXN];
    inline void dfs1(int u, int fa)
    {
        depth[u] = depth[fa] + 1;
        for(int v : e[u])
        {
            if(!(v ^ fa))
                continue;
            dfs1(v, u);
        }
    }
    int id[MAXN];
    inline void dfs2(int u, int fa, int op)
    {
        id[u] = op, depth[u] = depth[fa] + 1;
        for(int v : e[u])
        {
            if(!(v ^ fa))
                continue;
            dfs2(v, u, op);
        }
    }
    struct BitTree
    {
        int c[MAXN];
        inline int lowbit(int x)
        {
            return x & -x;
        }
        inline void update(int x, int k)
        {
            for(int i = x; i <= n; i += lowbit(i))
                c[i] += k;
        }
        inline int getsum(int x)
        {
            int ans = 0;
            for(int i = x; i >= 1; i -= lowbit(i))
                ans += c[i];
            return ans;
        }
        inline int query(int l, int r)
        {
            return getsum(r) - getsum(l - 1);
        }
    }T[2];
    bool vis[2][MAXN];
    int cnt[2][2][MAXN];
    int main()
    {
        scanf("%d", &n);
        for(int _ = 1, u, v; _ < n; _++)
        {
            scanf("%d%d", &u, &v);
            add(u, v), add(v, u);
        }
        scanf("%d%d%d", &sa, &sb, &q);
        for(int i = 1; i <= sa; i++)
            scanf("%d", &a[i]);
        for(int i = 1; i <= sb; i++)
            scanf("%d", &b[i]);
        dfs(1, 0);
        if(ps == 1)
        {
            dfs1(rt[1], 0);
            for(int i = 1; i <= sa; i++)
                vis[0][a[i]] = 1, T[0].update(depth[a[i]], 1);
            for(int i = 1; i <= sb; i++)
                vis[1][b[i]] = 1, T[1].update(depth[b[i]], 1);
            LL ans = 0;
            for(int i = 1; i <= sa; i++)
                ans += T[1].query(depth[a[i]], n) - vis[1][a[i]];
            printf("%lld\n", ans);
            char z, t;
            for(int _ = 1, w; _ <= q; _++)
            {
                std::cin >> z >> t;
                scanf("%d", &w);
                if(z == 'A')
                {
                    if(t == '+')
                        vis[0][w] = 1, T[0].update(depth[w], 1), ans += T[1].query(depth[w], n) - vis[1][w];
                    else vis[0][w] = 0, T[0].update(depth[w], -1), ans -= T[1].query(depth[w], n) - vis[1][w];
                }
                else
                {
                    if(t == '+')
                        vis[1][w] = 1, T[1].update(depth[w], 1), ans += T[0].query(1, depth[w]) - vis[0][w];
                    else vis[1][w] = 0, T[1].update(depth[w], -1), ans -= T[0].query(1, depth[w]) - vis[0][w];
                }
                printf("%lld\n", ans);
            }
        }
        else
        {
            dfs2(rt[1], rt[2], 0);
            depth[rt[1]] = 0;
            dfs2(rt[2], rt[1], 1);
            depth[rt[1]] = 1;
            for(int i = 1; i <= sa; i++)
                cnt[0][id[a[i]]][depth[a[i]]]++, vis[0][a[i]] = 1, T[0].update(depth[a[i]], 1);
            for(int i = 1; i <= sb; i++)
                cnt[1][id[b[i]]][depth[b[i]]]++, vis[1][b[i]] = 1, T[1].update(depth[b[i]], 1);
            LL ans = 0;
            for(int i = 1; i <= sa; i++)
                ans += T[1].query(depth[a[i]], n) - vis[1][a[i]] - cnt[1][!id[a[i]]][depth[a[i]]];
            printf("%lld\n", ans);
            char z, t;
            for(int _ = 1, w; _ <= q; _++)
            {
                std::cin >> z >> t;
                scanf("%d", &w);
                if(z == 'A')
                {
                    if(t == '+')
                        cnt[0][id[w]][depth[w]]++, vis[0][w] = 1, T[0].update(depth[w], 1), ans += T[1].query(depth[w], n) - vis[1][w] - cnt[1][!id[w]][depth[w]];
                    else cnt[0][id[w]][depth[w]]--, vis[0][w] = 0, T[0].update(depth[w], -1), ans -= T[1].query(depth[w], n) - vis[1][w] - cnt[1][!id[w]][depth[w]];
                }
                else
                {
                    if(t == '+')
                        cnt[1][id[w]][depth[w]]++, vis[1][w] = 1, T[1].update(depth[w], 1), ans += T[0].query(1, depth[w]) - vis[0][w] - cnt[0][!id[w]][depth[w]];
                    else cnt[1][id[w]][depth[w]]--, vis[1][w] = 0, T[1].update(depth[w], -1), ans -= T[0].query(1, depth[w]) - vis[0][w] - cnt[0][!id[w]][depth[w]];
                }
                printf("%lld\n", ans);
            }
        }
        return 0;
    }
    
    • 1

    [POI 2022/2023 R2] 涂色游戏 / Gra w kolorowanie

    信息

    ID
    3402
    时间
    6000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者