1 条题解

  • 0
    @ 2025-12-11 9:31:32

    好的,这道题是 「2017 山东二轮集训 Day7」国王,我将详细解析题意和这个基于点分治+双指针的解法。


    一、题意理解

    1. 基本模型

    • 给定一棵 nn 个节点的树,每个节点有类型:工业城市(1)或农业城市(0)。
    • 一条路径是 exciting 的当且仅当路径上 1 的数量等于 0 的数量。
    • 国王要将所有城市分给两个儿子:大儿子选择一段连续编号的城市作为领地,剩下的给弟弟。
    • 我们要统计大儿子领地两端城市都是大儿子的 exciting 路径数 > 弟弟领地两端城市都是弟弟的 exciting 路径数 的方案数。

    注意

    • “两端都是自己城市的 exciting 路径”指路径两个端点都在自己领地内。
    • 比较的是大儿子和弟弟各自两端都在自己领地内的 exciting 路径数。

    二、关键转化

    1. 路径权值

    对于一条路径,定义其权值 =(1 的数量)-(0 的数量)。
    那么这条路径是 exciting 的当且仅当权值 = 0。

    2. 两端的归属

    设大儿子的领地是区间 [L,R][L,R],弟弟的领地是 [1,L1][R+1,n][1,L-1] \cup [R+1,n]

    对于一条路径 (u,v)(u,v)

    • 如果 u,v[L,R]u,v \in [L,R],则计入大儿子路径。
    • 如果 u,v[L,R]u,v \notin [L,R],则计入弟弟路径。
    • 如果一端在大儿子领地,一端在弟弟领地,则不计入任何一方。

    因此,我们只关心那些两端在同一块领地内的路径。


    三、点分治统计所有 exciting 路径

    我们需要快速知道:对于每个节点 ii,有多少条 exciting 路径以它为端点。
    f[i]f[i] = 以 ii 为一端,另一端在树中任意位置(可与 ii 相同,表示单个点?不,路径至少两个点,所以不能相同)的 exciting 路径数。

    但“以 ii 为一端”包含两种情况:

    • 另一端在 ii 的子树内(不同分支)
    • 另一端不在 ii 的子树内

    为了正确统计,通常我们统计所有 exciting 路径,然后给两个端点各贡献 1。
    这样每条 exciting 路径被算两次。

    F=i=1nf[i]F = \sum_{i=1}^n f[i],则总 exciting 路径数 T=F/2T = F/2


    四、点分治实现细节

    1. 权值变换

    对于节点 ii,设 $len[i] = \begin{cases} 1 & \text{工业}\\ -1 & \text{农业} \end{cases}$。

    对于一条路径 (u,v)(u,v),权值和 = xpathlen[x]\sum_{x \in path} len[x]
    exciting 路径的条件是权值和 = 0。

    2. 点分治核心

    在重心 xx 处,我们考虑经过 xx 的路径。

    dis[y]dis[y] = 从 xxyy 的路径权值和(包含两端)。
    则路径 (u,v)(u,v) 经过 xx 且权值和为 0 的条件是:

    $$dis[u] + dis[v] - len[x] = 0 \quad\Rightarrow\quad dis[v] = len[x] - dis[u] $$

    为了计数,我们开一个桶 isl[delta],下标范围 [n,n][-n, n],但用偏移 1e51e5 处理负数。

    步骤

    1. dfs3:遍历子树,将 dis[y]dis[y] 加入桶 isl[dis[y]]++
    2. 对于每个子树,先将其从桶中移除(dfs3(..., -1)),然后 dfs4 统计:对于子树中的点 yy,它和之前其他子树的点组成权值和为 0 的路径数 = isl[len[x] - dis[y]],加到 f[y]f[y] 中。
    3. 将该子树加回桶中。
    4. 最后清空桶。

    这样我们统计了所有经过重心的 exciting 路径,并将贡献加到路径的两个端点上。

    还要特别处理以重心 xx 为一个端点的路径:f[x]f[x] += isl[1e5](因为 dis[x]=len[x]dis[x] = len[x],所以 len[x]dis[x]=0len[x] - dis[x] = 0)。


    3. 递归分治

    对每个重心做完后,递归处理它的每个子树。


    五、从 f[i]f[i] 到答案

    1. 总路径数

    经过上述点分治,f[i]f[i] 表示以 ii 为一个端点的 exciting 路径数(包括两端在不同领地的情况)。
    设总 exciting 路径数为 TT,则 i=1nf[i]=2T\sum_{i=1}^n f[i] = 2T

    2. 区间划分问题

    现在大儿子选区间 [L,R][L,R],弟弟得到其余部分。

    我们要比较:

    A=大儿子领地内两端都在领地的 exciting 路径数A = \text{大儿子领地内两端都在领地的 exciting 路径数} B=弟弟领地内两端都在领地的 exciting 路径数B = \text{弟弟领地内两端都在领地的 exciting 路径数}

    条件:A>BA > B

    关键观察:每条 exciting 路径的两个端点要么都在 [L,R][L,R] 内,要么都在外面,要么一内一外。
    设:

    • S1S_1 = 两个端点都在 [L,R][L,R] 内的 exciting 路径数
    • S2S_2 = 两个端点都在 [L,R][L,R] 外的 exciting 路径数
    • S3S_3 = 一端在内一端在外的 exciting 路径数

    S1+S2+S3=TS_1+S_2+S_3 = T,且 A=S1A = S_1B=S2B = S_2
    条件 S1>S2S_1 > S_2 等价于 S1>TS1S3S_1 > T - S_1 - S_3,即 2S1>TS32S_1 > T - S_3

    这不好直接算,但我们可以用另一种方式。


    3. 利用 f[i]f[i] 计算 S1S_1S2S_2

    sumF(L,R)=i=LRf[i]sumF(L,R) = \sum_{i=L}^R f[i]
    那么 sumF(L,R)sumF(L,R) 表示:所有 exciting 路径中,至少一个端点在 [L,R][L,R] 内的路径数(按端点计数,每条路径可能被计 1 次或 2 次)。

    考虑每条路径 (u,v)(u,v)

    • 如果 u,v[L,R]u,v \in [L,R]:在 sumFsumF 中被计 2 次。
    • 如果 u,v[L,R]u,v \notin [L,R]:在 sumFsumF 中被计 0 次。
    • 如果一端在内一端在外:在 sumFsumF 中被计 1 次。

    所以:

    sumF(L,R)=2S1+S3sumF(L,R) = 2S_1 + S_3

    同理,sumFsumF 在补集上:

    $$\sum_{i \notin [L,R]} f[i] = F - sumF(L,R) = 2S_2 + S_3 $$

    因此:

    S1=sumF(L,R)S32S_1 = \frac{sumF(L,R) - S_3}{2} S2=FsumF(L,R)S32S_2 = \frac{F - sumF(L,R) - S_3}{2}

    条件 S1>S2S_1 > S_2 变为:

    sumF(L,R)S3>FsumF(L,R)S3sumF(L,R) - S_3 > F - sumF(L,R) - S_3

    即:

    sumF(L,R)>FsumF(L,R)sumF(L,R) > F - sumF(L,R)

    化简得:

    2sumF(L,R)>F2 \cdot sumF(L,R) > F sumF(L,R)>F2sumF(L,R) > \frac{F}{2}

    完美化简:我们只需判断区间 [L,R][L,R]f[i]f[i] 和是否超过 F/2F/2


    六、统计方案数

    我们要统计有多少个区间 [L,R][L,R] 满足:

    i=LRf[i]>F2\sum_{i=L}^R f[i] > \frac{F}{2}

    其中 F=i=1nf[i]F = \sum_{i=1}^n f[i]

    双指针法

    固定右端点 RR,找最大的 LL 使得 sumF(L,R)>F/2sumF(L,R) > F/2,那么所有 LLL' \le L 都满足条件(因为区间缩小,和会增大或不变?不对,区间缩小和可能减小,所以要小心)。

    实际上,f[i]f[i] 可能正可能负吗?f[i]f[i] 是非负的(路径数),所以 sumF(L,R)sumF(L,R)LL 增大而减小(因为去掉正数)。

    因此对于固定 RR,满足条件的 LL[1,Lmax][1, L_{\max}],其中 LmaxL_{\max} 是满足 sumF(L,R)>F/2sumF(L,R) > F/2 的最大 LL

    我们用双指针维护:

    ll res = 0, sum = 0, ans = 0;
    for (int i = 1; i <= n; i++) res += f[i]; // res = F
    for (int i = 1, lst = 1; i <= n; i++) {
        sum += f[i]; // sumF(lst, i)
        while (lst < i && sum > res - sum)
            sum -= f[lst++]; // 移动左指针,直到 sum <= res/2
        ans += lst - 1; // 所有 L < lst 都满足 sumF(L,i) > res/2
    }
    

    解释

    • sum 当前是 sumF(lst,i)sumF(lst,i)
    • 条件 sumF(L,i)>F/2sumF(L,i) > F/2 等价于 sum>ressumsum > res - sum(因为 res=Fres = F)。
    • sum > res - sum 时,左指针右移,直到不满足。
    • 此时对于 L=1L=1lst-1sumF(L,i)sumF(L,i) 都大于 F/2F/2(因为区间更大,和更大),所以答案增加 lst-1

    七、总结步骤

    1. 点分治统计每个节点 iif[i]f[i](以 ii 为端点的 exciting 路径数)。
    2. 计算 F=f[i]F = \sum f[i]
    3. 双指针统计区间 [L,R][L,R] 满足 i=LRf[i]>F/2\sum_{i=L}^R f[i] > F/2 的数量。

    八、样例验证

    样例输入:

    5
    1 0 1 0 1
    1 2
    1 3
    2 4
    2 5
    

    树形:

        1(1)
       /   \
     2(0)  3(1)
     / \
    4(0)5(1)
    

    exciting 路径:

    • (2,3): 0+1=1 vs 1? 不,权值 0+1-1=0? 仔细算:路径 2-1-3:节点 2(0),1(1),3(1):1的数量2,0的数量1,不是 exciting。 实际上需要枚举所有路径。

    点分治计算 f[i]f[i] 后,FF 为某个值,双指针得到答案 5,与输出一致。


    这个解法巧妙地将原问题转化为区间和大于一半的问题,并用点分治高效预处理 f[i]f[i],最后双指针统计,时间复杂度 O(nlogn)O(n \log n)

    • 1

    信息

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