题目大意

给出一棵树,边上有权值,要求给出一个1到n的排列p,使得sigma d(i, pi)最大,且p的字典序尽量小。

d(u, v)为树上两点u和v的距离

题解:一开始没看出来p需要每个数都不同,直接敲了个轻重边剖分orz,交上去才发现不对

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <vector>
  5. #define fi first
  6. #define se second
  7. using namespace std;
  8. typedef long long LL;
  9. typedef pair<int, int> PII;
  10. typedef pair<long long, int> PLI;
  11. const int maxn = 1e5 + ;
  12. PLI dp[maxn], dp2[maxn];
  13. vector<PII> G[maxn];
  14. int son[maxn];
  15.  
  16. void dfs(int x, int fa){
  17. dp[x].se = x;
  18. dp[x].fi = ;
  19. for(auto e : G[x]){
  20. if(e.fi == fa) continue;
  21. dfs(e.fi, x);
  22. if(dp[e.fi].fi + e.se >= dp[x].fi){
  23. if(dp[e.fi].fi + e.se == dp[x].fi){
  24. son[x] = dp[x].se < dp[e.fi].se ? son[x] : e.fi;
  25. dp[x].se = min(dp[x].se, dp[e.fi].se);
  26. } else {
  27. son[x] = e.fi;
  28. dp[x].fi = dp[e.fi].fi + e.se;
  29. dp[x].se = dp[e.fi].se;
  30. }
  31. }
  32. }
  33. }
  34.  
  35. void Maintain(LL v, PLI A, PLI& B){
  36. if(v + A.fi > B.fi){
  37. B.fi = v + A.fi;
  38. B.se = A.se;
  39. } else if(v + A.fi == B.fi){
  40. B.se = B.se < A.se ? B.se : A.se;
  41. }
  42. }
  43.  
  44. void ddfs(int x, int fa, LL v){
  45. dp2[x].se = x;
  46. for(auto e : G[x]){
  47. if(e.fi == fa) continue;
  48. if(e.fi == son[x]) continue;
  49. Maintain(e.se, dp[e.fi], dp2[x]);
  50. }
  51. if(son[fa] == x){
  52. Maintain(v, dp2[fa], dp2[x]);
  53. } else {
  54. Maintain(v, dp[fa], dp2[x]);
  55. Maintain(v, dp2[fa], dp2[x]);
  56. }
  57. for(auto e : G[x]) if(e.fi != fa) ddfs(e.fi, x, e.se);
  58. }
  59.  
  60. int main()
  61. {
  62. int n, x, y, w;
  63. cin>>n;
  64. for(int i = ; i < n; i++){
  65. cin>>x>>y>>w;
  66. G[x].push_back({y, w});
  67. G[y].push_back({x, w});
  68. }
  69. dfs(, );
  70. LL ans = ;
  71. vector<int> V;
  72. ans += dp[].fi; V.push_back(dp[].se);
  73. dp2[].se = ;
  74. for(auto e : G[]){
  75. if(e.fi == son[]) continue;
  76. Maintain(e.se, dp[e.fi], dp2[]);
  77. }
  78. for(auto e : G[]) ddfs(e.fi, , e.se);
  79. for(int i = ; i <= n; i++){
  80. if(dp[i].fi > dp2[i].fi){
  81. ans += dp[i].fi;
  82. V.push_back(dp[i].se);
  83. } else if(dp[i].fi == dp2[i].fi){
  84. ans += dp[i].fi;
  85. V.push_back(dp[i].se < dp2[i].se ? dp[i].se : dp2[i].se);
  86. } else {
  87. ans += dp2[i].fi;
  88. V.push_back(dp2[i].se);
  89. }
  90. }
  91. cout<<ans<<endl;
  92. for(auto x : V) cout<<x<<" ";
  93.  
  94. }

题解2:

如果排列要求都不同的话,实际上求最大值反而好求了

考虑在以任意点x为根,u和v匹配的答案

就是dis(x, u) + dis(x, v) - dis(x, lca(u, v))

如果这个点x是树的重心,我们就可以使得每个匹配的lca都是x,这时就可以得到最优解

所以求最优解还是很容易的

接下来是匹配

匹配实际上并不好做,需要考虑下面几个问题

1、找到树的重心以后,需要把每颗子树的dfs序用线段树维护,然后用线段树查询值最小的点

2、在匹配的过程中,有可能出现如果把u和v匹配之后,后面就无法完成匹配的情况,这时只能用u来匹配最需要匹配的那棵子树

这个理解起来可能比较抽象,写成具体的式子实际上是

令px[i]表示子树i内还有多少个点没有跟其他子树中的点匹配

py[i]表示子树i内还有多少个点没有被(强调被动)其他子树中的点匹配

如果当前还有y个点没进行匹配,那么如果存在一颗子树i, y < px[i] + py[i],实际上就必须要优先考虑i子树了。

因为如果还是按照字典序匹配,就会造成后续的i子树外需要匹配的点的个数,小于i子树内需要被匹配的点的个数,就根本无法完成匹配!

当然如果这个点本身还是在i子树内的话,那么还是可以和其他子树匹配的,(因为y和px[i]同时减1,不影响后续匹配)

3、重心可以和重心本身匹配,这很扯。。但是确实是可行的,需要特殊考虑

实现过程的时候,用set来维护px[i] + py[i],如果出现了y < px[i] + py[i],就进行特殊处理。

没出现就按字典序查询匹配。整个过程都要动态维护px[i], py[i]的值

然后线段树维护dfs序不再多说。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <vector>
  5. #include <set>
  6. #define fi first
  7. #define se second
  8. using namespace std;
  9. const int maxn = 1e5 + ;
  10. typedef long long LL;
  11. typedef pair<long long, int> PLI;
  12. typedef pair<int, int> PII;
  13. vector<PLI> G[maxn];
  14. set<PII> S;
  15. int son[maxn], sz[maxn], f[maxn], col[maxn], ll[maxn], rr[maxn], no[maxn], ans[maxn], M[maxn];
  16. int tree[maxn*];
  17. int n, tot;
  18. LL ANS = ;
  19. void dfs0(int x, int fa){
  20. sz[x] = ;
  21. for(auto e : G[x]){
  22. if(e.fi == fa) continue;
  23. dfs0(e.fi, x);
  24. sz[x] += sz[e.fi];
  25. son[x] = max(son[x], sz[e.fi]);
  26. }
  27. son[x] = max(son[x], n - sz[x]);
  28. }
  29.  
  30. void dfs(int x, int fa, LL v){
  31. sz[x] = ;
  32. for(auto e : G[x]){
  33. if(e.fi == fa) continue;
  34. dfs(e.fi, x, e.se+v);
  35. sz[x] += sz[e.fi];
  36. }
  37. ANS += v;
  38. }
  39.  
  40. void Insert(int o, int l, int r, int k, int v){
  41. if(l == r) { tree[o] = v; return; }
  42. int mid = (l+r)>>;
  43. if(k <= mid) Insert(o*, l, mid, k, v);
  44. else Insert(o*+, mid+, r, k, v);
  45. tree[o] = min(tree[o*], tree[o*+]);
  46. }
  47. int Query(int o, int l, int r, int L, int R){
  48. if(L <= l && r <= R) return tree[o];
  49. int mid = (l+r)>>, ans = 1e9;
  50. if(L <= mid) ans = min(ans, Query(o*, l, mid, L, R));
  51. if(R > mid) ans = min(ans, Query(o*+, mid+, r, L, R));
  52. return ans;
  53. }
  54.  
  55. void dfs1(int x, int fa, int cc){
  56. f[x] = ++tot;
  57. col[x] = cc;
  58. Insert(, , n, tot, x);
  59. for(auto e : G[x]){
  60. if(e.fi == fa) continue;
  61. dfs1(e.fi, x, cc);
  62. }
  63. }
  64.  
  65. void Erase(int col){
  66. PII x = make_pair(-M[col]-no[col], col);
  67. S.erase(x);
  68. if(x.fi+ < ) S.insert({x.fi+, col});
  69. }
  70.  
  71. int main()
  72. {
  73. cin>>n;
  74. for(int i = ; i < n; i++){
  75. int x, y, w;
  76. cin>>x>>y>>w;
  77. G[x].push_back({y, w});
  78. G[y].push_back({x, w});
  79. }
  80. int X;
  81. dfs0(, );
  82. for(int i = ; i <= n; i++) if(son[i] <= n/) X = i;
  83. dfs(X, X, );
  84. cout<<ANS*<<endl;
  85. int flag = , N = ;
  86. for(auto e : G[X]){
  87. ll[++N] = tot+;
  88. dfs1(e.fi, X, N);
  89. rr[N] = tot;
  90. S.insert({-*sz[e.fi], N});
  91. M[N] = no[N] = sz[e.fi];
  92. }
  93. f[X] = ++tot;
  94. Insert(, , n, tot, X);
  95. ll[++N] = tot;
  96. rr[N] = tot;
  97. col[X] = N;
  98. S.insert({, N});
  99. M[N] = no[N] = ;
  100. int l, r;
  101. for(int i = ; i <= n; i++){
  102. auto x = *S.begin();
  103. int rem = n-i+;
  104. if(col[i] != x.se){
  105. rem--;
  106. if(rem < -x.fi){
  107. l = ll[x.se], r = rr[x.se];
  108. int y = Query(, , n, l, r);
  109. ans[i] = y;
  110. Erase(x.se);
  111. M[x.se]--;
  112. Insert(, , n, f[y], 1e9);
  113. Erase(col[i]);
  114. no[col[i]]--;
  115. continue;
  116. }
  117. }
  118. l = ll[col[i]], r = rr[col[i]];
  119. int y = 1e9;
  120. if(l- > ) y = min(y, Query(, , n, , l-));
  121. if(r+ <= n) y = min(y, Query(, , n, r+, n));
  122. if(f[i] == n) y = min(i, y);
  123. Insert(, , n, f[y], 1e9);
  124. ans[i] = y;
  125. Erase(col[i]);
  126. no[col[i]]--;
  127. Erase(col[y]);
  128. M[col[y]]--;
  129. }
  130. for(int i = ; i <= n; i++) cout<<ans[i]<<" ";
  131. }

Codeforces Round #268 (Div. 1) 468D Tree(杜教题+树的重心+线段树+set)的更多相关文章

  1. Codeforces Round #268 (Div. 2) ABCD

    CF469 Codeforces Round #268 (Div. 2) http://codeforces.com/contest/469 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...

  2. Codeforces Round #499 (Div. 1) F. Tree

    Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...

  3. Codeforces Round #367 (Div. 2) A. Beru-taxi (水题)

    Beru-taxi 题目链接: http://codeforces.com/contest/706/problem/A Description Vasiliy lives at point (a, b ...

  4. Codeforces Round #575 (Div. 3) 昨天的div3 补题

    Codeforces Round #575 (Div. 3) 这个div3打的太差了,心态都崩了. B. Odd Sum Segments B 题我就想了很久,这个题目我是找的奇数的个数,因为奇数想分 ...

  5. 数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction

    Tree Construction Problem's Link ------------------------------------------------------------------- ...

  6. Codeforces Round #334 (Div. 2) A. Uncowed Forces 水题

    A. Uncowed Forces Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/604/pro ...

  7. Codeforces Round #353 (Div. 2) D. Tree Construction 二叉搜索树

    题目链接: http://codeforces.com/contest/675/problem/D 题意: 给你一系列点,叫你构造二叉搜索树,并且按输入顺序输出除根节点以外的所有节点的父亲. 题解: ...

  8. Codeforces Round #540 (Div. 3)--1118F1 - Tree Cutting (Easy Version)

    https://codeforces.com/contest/1118/problem/F1 #include<bits/stdc++.h> using namespace std; in ...

  9. Codeforces Round #353 (Div. 2) D. Tree Construction 模拟

    D. Tree Construction 题目连接: http://www.codeforces.com/contest/675/problem/D Description During the pr ...

随机推荐

  1. 如何用 npm 同时执行两条监听命令

    在日常项目中启动项目 需要启动项目可能需要不止一条命令 这就很麻烦 要开启两个bash 很麻烦 终于找到了比较好的解决方案 例如我的: npm run dev //启动项目项目 npm run jso ...

  2. 20.2 解析与序列化【JavaScript高级程序设计第三版】

    JSON 之所以流行,拥有与JavaScript 类似的语法并不是全部原因.更重要的一个原因是,可以把JSON 数据结构解析为有用的JavaScript 对象.与XML 数据结构要解析成DOM 文档而 ...

  3. scala成长之路(3)隐式转换

    不废话,先上例子:定义一个参数类型为String的函数: scala> def sayHello(name:String) = println("hello " + name ...

  4. Python爬虫爬取百度翻译之数据提取方法json

    工具:Python 3.6.5.PyCharm开发工具.Windows 10 操作系统 说明:本例为实现输入中文翻译为英文的小程序,适合Python爬虫的初学者一起学习,感兴趣的可以做英文翻译为中文的 ...

  5. ABAP CDS ON HANA-(8)算術式

    Arithmetic expression in CDS View Allowed Arithmetic operators in CDS view. CDS View- @AbapCatalog.s ...

  6. ABAP CDS ON HANA-(5)テーブル結合ビュー

    JOINs in CDS View In ABAP CDS, Join between two data sources is allowed. Allowed joins are:- Inner J ...

  7. (转载)深入super,看Python如何解决钻石继承难题

    1.   Python的继承以及调用父类成员 python子类调用父类成员有2种方法,分别是普通方法和super方法 假设Base是基类 class Base(object): def __init_ ...

  8. Jquery操作select选项集合!

    Query获取Select选择的Text和Value: 1. $("#select_id").change(function(){//code...}); //为Select添加事 ...

  9. PostgreSQL 10.0 压缩版的 pgAdmin 不能用的问题

    PostgreSQL终于发布10.0正式版了!下载压缩版的更新了一下本机的版本,然后打开pgAdmin的时候总是报错“The application server could not be conta ...

  10. 不用找了,比较全的signalR例子已经为你准备好了(2)---JqGrid 服务端刷新方式-注释详细-DEMO源码下载

    上次用客户端进行数据刷新的方式,和官方的Demo实现存在差异性,今天花了一点时间好好研究了一下后台时时刷新的方式.将写的代码重新update了一次,在这之前找过好多的资料,发现都没有找到好的例子,自己 ...