4 条题解

  • 0
    @ 2024-8-11 21:29:49

    妙妙题。

    下文中令根节点的深度为 00

    我们先考虑如何找出根节点 rr,显然的有 $f_{r,k} = \bigoplus\limits_{u = 1}^n [\text{dep}_u = k]w_u$,我们不妨思考如何求出 $g_k = \bigoplus\limits_{u = 1}^n [\text{dep}_u = k]w_u$。

    结论 1:所有 fu,k+1f_{u, k + 1} 的异或和即为 u=1n[depu=k]wu\bigoplus\limits_{u = 1}^n [\text{dep}_u = k]w_u

    对于每个 uu 计算出到其距离为 k+1k + 1 的节点个数的奇偶性,从而判断其对答案有无贡献。

    depu=k\text{dep}_u = k,则在 uu 子树内有偶数个节点到 uu 的距离为 k+1k + 1,在 uu 的子树外只有 11 个节点到 uu 的距离为 k+1k + 1(不妨假设 uu 在根节点的左子树中,那么唯一的节点 vv 就是根节点的右儿子),总个数为奇数,其对答案的贡献为 wuw_u

    depu<k\text{dep}_u \lt k,子树内仍然是有偶数个节点,子树外的部分,我们考虑 uu 的每个祖先 ff(不妨设 uuff 的左子树内),钦定 vvff 的右子树内,则对于每个 ff,我们都有偶数个节点 vv 满足条件,于是其对答案的贡献为 00

    depu>k\text{dep}_u \gt k,子树内同理,子树外还是考虑 uu 的每个祖先 ff,对于 depudepf<k\text{dep}_u - \text{dep}_f\lt k 的祖先,我们都有偶数个满足条件的 vv,对于 depudepf=k\text{dep}_u - \text{dep}_f = k 的祖先,我们只有一个节点(即 ff 的右儿子)满足条件,对于 depudepf=k+1\text{dep}_u - \text{dep}_f = k + 1 的祖先,同样也只有一个节点(即 ff 本身)满足条件,所以总个数为偶数,对答案贡献为 00

    于是,只有深度为 kk 的节点会被计算贡献,也就证明了上述引理。

    现在我们已经求出了 gkg_k,我们将其与每个节点的 ff 逐一比对,找出根节点 rr(注意要判断 khk\geq h 时,fr,kf_{r, k} 是否全为 00)。

    接下来我们考虑如何求出根节点的权值,注意到我们只需求出所有节点的权值异或和即可,于是问题转化为如何求出所有节点的权值异或和。

    结论 2:对于两个节点 u,vu, v,若 dis(u,v)\text{dis}(u, v) 为奇数,则所有点权的异或和即为:

    $$\bigoplus\limits_{k = 1}^{2h - 2}[2\nmid k]f_{u, k}\oplus f_{v, k} $$

    dis(u,v)\text{dis}(u, v) 为偶数,则上述式子为 00

    我们要证明的就是,对于两个节点 u,vu, v,若 dis(u,v)\text{dis}(u, v) 为奇数,则到 uu 距离为奇数的点集 SuS_u 和到 vv 距离为奇数的点集 SvS_v 交集为空,且并集为全集。

    其实已经很显然了,对于一个节点,要么它到 uu 的距离为奇数,要么它到 vv 的距离为奇数,容易证明这两者是对立的。

    u,vu, v 距离为偶数的证明也是类似,这里不再赘述。

    于是我们只需随意固定一个点,枚举另外一个点,根据结论 2 中的式子求出异或和,若该值不为 00,则所有点权的异或和即为该值(如果得到的所有值均为 00,那么说明所有点权的异或和就是 00),然后就能求出根节点的权值 ww

    总的时间复杂度为 O(h2h)\mathcal{O}(h2^h)

    #include <bits/stdc++.h>
    
    using i64 = long long;
    
    constexpr int N = 1e5 + 5, LOG = 16;
    
    int T, n, h;
    int f[N][LOG << 1], g[LOG];
    
    void solve() {
    	std::cin >> h; n = (1 << h) - 1;
    	for (int u = 1; u <= n; u++) for (int k = 1; k <= 2 * h - 2; k++) std::cin >> f[u][k];
    	for (int k = 1; k < h; k++) {
    		g[k] = 0;
    		for (int u = 1; u <= n; u++) g[k] ^= f[u][k + 1];
    	}
    	for (int u = 1; u <= n; u++) {
    		bool ok = true;
    		for (int k = 1; k < h; k++) ok &= (g[k] == f[u][k]);
    		for (int k = h; k <= 2 * h - 2; k++) ok &= (f[u][k] == 0);
    		if (ok) {
    			int v1 = (u == 1 ? 2 : 1), all = 0;
    			for (int v2 = 1; v2 <= n; v2++) if (v1 != v2) {
    				all = 0;
    				for (int k = 1; k <= 2 * h - 2; k += 2) all ^= f[v1][k] ^ f[v2][k];
    				if (all != 0) break;
    			}
    			int w = all;
    			for (int k = 1; k < h; k++) w ^= f[u][k];
    			return std::cout << u << " " << w << "\n", void();
    		}
    	}
    }
    
    int main() {
    
    	std::ios::sync_with_stdio(false);
    	std::cin.tie(nullptr);
    
    	std::cin >> T;
    	while (T--) solve();
    
    	return 0;
    }
    

    信息

    ID
    31
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    243
    已通过
    18
    上传者