ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

构造

2022-08-29 23:33:48  阅读:266  来源: 互联网

标签:nxt cnt int 构造 权值 pair 节点


构造题常常需要发现一些隐蔽的性质。提高观察力!

CF1670E

题目大意

给定一个 \(n = 2^p\) 个节点的树的形态,需要给每个点和每条边赋权值,一共 \(n\) 个点和 \(n-1\) 条边,权值在\([1, 2n-1]\) 里面选并且不能重复。然后钦定一个根节点。

需要使根节点到每个点和每条边的路径上的权值异或和的最大值最小\(^{*}\),求构造方案。

\(^{*}\) 比如下图,\(p=2\),根节点是权值为 \(3\) 的点:
image
所有参与比较的异或和为:
\(3 ;\)
\(3⊕7=4;\)
\(3⊕7⊕6=2;\)
\(3⊕2=1;\)
\(3⊕2⊕1=0;\)
\(3⊕2⊕1⊕4=4;\)
\(3⊕2⊕1⊕4⊕5=1.\)
最大值为 \(4\),是该形态树的一个最优解。

题目分析

观察性质,可以看出这个最小的最大值(简记为答案)应该是 \(n = 2^p\):

由于存在 \(2^p \sim 2^{p + 1}\) 的权值并且每个权值至少贡献一次,所以当第一次碰到这类权值的时候,异或和的第 \(p+1\) 位是 \(1\),因此答案不会小于 \(2^p\)。

考虑如何构造一颗满足答案为 \(n\) 的树。

我们有如下做法:

  • 任意取根节点,并将 \(n\) 作为根节点权值。
  • 从根节点开始,每向下拓展一层,对于下一层的点和这两个点之间的连边做如下赋值操作:如果这一层的点权为 \(1 \sim n-1\), 那么将边权赋 \(n + k\), 下一层的点权赋 \(k\)(\(k \in [1, n - 1]\),不取重复值)

为什么此法可行?因为每一条链上的异或和都是形如
\(n\)
\(n ⊕ n+k_1 = k_1 < n\)
\(n ⊕ n+k_1 ⊕ k_1 = 0\)
\(n ⊕ n+k_1 ⊕ k_1 ⊕ k_2 = k_2 < n\)
\(n ⊕ n+k_1 ⊕ k_1 ⊕ k_2 ⊕ n+k_2 = n\)
\(n ⊕ n+k_1 ⊕ k_1 ⊕ k_2 ⊕ n+k_2 ⊕ n+k_3 = n ⊕ n+k_3 = k_3 < n\)
\(...\)
这样的东西,满足要求。

个人代码

#include<bits/stdc++.h>
using namespace std;
#define f(i, a, b) for(int i = a; i <= b; i++)
#define mod9 998244353
#define mod1 1000000007
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define endl '\n'
vector<vector<int>> g;
int cnt, n;
int node[300010], ver[300010];
map<pii, int> m;
void dfs(int x, int fa) {
    f(i, 0, g[x].size() - 1) {
        if(g[x][i] != fa) {
            int nxt = g[x][i];
            if(node[x] >= n) {
                int v = m[make_pair(x, nxt)];
                ver[v] = n + cnt; node[nxt] = cnt;
                cnt++;
            }
            else {
                int v = m[make_pair(x, nxt)];
                ver[v] = cnt; node[nxt] = n + cnt;     
                cnt++;       
            }
            dfs(nxt, x);
        }
    }
}
 
int main(){
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    int t; cin >> t;
    while(t--) {
        int p; cin >> p; n = (1 << p);
        g.clear(); g.resize(n + 5);
        f(i, 1, n - 1) {
            int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); 
            m[make_pair(u, v)] = i; m[make_pair(v, u)] = i;
        }
        cnt = 1;
        cout << 1 << endl;
        node[1] = n;
        dfs(1, 0);
        f(i, 1, n) cout << node[i] << " \n"[i == n];
        f(i, 1, n - 1) cout << ver[i] << " \n"[i == n - 1];
    }
    
    return 0;
}

标签:nxt,cnt,int,构造,权值,pair,节点
来源: https://www.cnblogs.com/Zeardoe/p/16637791.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有