Codeforces Round #268 (Div. 1) 468D Tree(杜教题+树的重心+线段树+set)
题目大意
给出一棵树,边上有权值,要求给出一个1到n的排列p,使得sigma d(i, pi)最大,且p的字典序尽量小。
d(u, v)为树上两点u和v的距离
题解:一开始没看出来p需要每个数都不同,直接敲了个轻重边剖分orz,交上去才发现不对
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <vector>
- #define fi first
- #define se second
- using namespace std;
- typedef long long LL;
- typedef pair<int, int> PII;
- typedef pair<long long, int> PLI;
- const int maxn = 1e5 + ;
- PLI dp[maxn], dp2[maxn];
- vector<PII> G[maxn];
- int son[maxn];
- void dfs(int x, int fa){
- dp[x].se = x;
- dp[x].fi = ;
- for(auto e : G[x]){
- if(e.fi == fa) continue;
- dfs(e.fi, x);
- if(dp[e.fi].fi + e.se >= dp[x].fi){
- if(dp[e.fi].fi + e.se == dp[x].fi){
- son[x] = dp[x].se < dp[e.fi].se ? son[x] : e.fi;
- dp[x].se = min(dp[x].se, dp[e.fi].se);
- } else {
- son[x] = e.fi;
- dp[x].fi = dp[e.fi].fi + e.se;
- dp[x].se = dp[e.fi].se;
- }
- }
- }
- }
- void Maintain(LL v, PLI A, PLI& B){
- if(v + A.fi > B.fi){
- B.fi = v + A.fi;
- B.se = A.se;
- } else if(v + A.fi == B.fi){
- B.se = B.se < A.se ? B.se : A.se;
- }
- }
- void ddfs(int x, int fa, LL v){
- dp2[x].se = x;
- for(auto e : G[x]){
- if(e.fi == fa) continue;
- if(e.fi == son[x]) continue;
- Maintain(e.se, dp[e.fi], dp2[x]);
- }
- if(son[fa] == x){
- Maintain(v, dp2[fa], dp2[x]);
- } else {
- Maintain(v, dp[fa], dp2[x]);
- Maintain(v, dp2[fa], dp2[x]);
- }
- for(auto e : G[x]) if(e.fi != fa) ddfs(e.fi, x, e.se);
- }
- int main()
- {
- int n, x, y, w;
- cin>>n;
- for(int i = ; i < n; i++){
- cin>>x>>y>>w;
- G[x].push_back({y, w});
- G[y].push_back({x, w});
- }
- dfs(, );
- LL ans = ;
- vector<int> V;
- ans += dp[].fi; V.push_back(dp[].se);
- dp2[].se = ;
- for(auto e : G[]){
- if(e.fi == son[]) continue;
- Maintain(e.se, dp[e.fi], dp2[]);
- }
- for(auto e : G[]) ddfs(e.fi, , e.se);
- for(int i = ; i <= n; i++){
- if(dp[i].fi > dp2[i].fi){
- ans += dp[i].fi;
- V.push_back(dp[i].se);
- } else if(dp[i].fi == dp2[i].fi){
- ans += dp[i].fi;
- V.push_back(dp[i].se < dp2[i].se ? dp[i].se : dp2[i].se);
- } else {
- ans += dp2[i].fi;
- V.push_back(dp2[i].se);
- }
- }
- cout<<ans<<endl;
- for(auto x : V) cout<<x<<" ";
- }
题解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序不再多说。
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <vector>
- #include <set>
- #define fi first
- #define se second
- using namespace std;
- const int maxn = 1e5 + ;
- typedef long long LL;
- typedef pair<long long, int> PLI;
- typedef pair<int, int> PII;
- vector<PLI> G[maxn];
- set<PII> S;
- int son[maxn], sz[maxn], f[maxn], col[maxn], ll[maxn], rr[maxn], no[maxn], ans[maxn], M[maxn];
- int tree[maxn*];
- int n, tot;
- LL ANS = ;
- void dfs0(int x, int fa){
- sz[x] = ;
- for(auto e : G[x]){
- if(e.fi == fa) continue;
- dfs0(e.fi, x);
- sz[x] += sz[e.fi];
- son[x] = max(son[x], sz[e.fi]);
- }
- son[x] = max(son[x], n - sz[x]);
- }
- void dfs(int x, int fa, LL v){
- sz[x] = ;
- for(auto e : G[x]){
- if(e.fi == fa) continue;
- dfs(e.fi, x, e.se+v);
- sz[x] += sz[e.fi];
- }
- ANS += v;
- }
- void Insert(int o, int l, int r, int k, int v){
- if(l == r) { tree[o] = v; return; }
- int mid = (l+r)>>;
- if(k <= mid) Insert(o*, l, mid, k, v);
- else Insert(o*+, mid+, r, k, v);
- tree[o] = min(tree[o*], tree[o*+]);
- }
- int Query(int o, int l, int r, int L, int R){
- if(L <= l && r <= R) return tree[o];
- int mid = (l+r)>>, ans = 1e9;
- if(L <= mid) ans = min(ans, Query(o*, l, mid, L, R));
- if(R > mid) ans = min(ans, Query(o*+, mid+, r, L, R));
- return ans;
- }
- void dfs1(int x, int fa, int cc){
- f[x] = ++tot;
- col[x] = cc;
- Insert(, , n, tot, x);
- for(auto e : G[x]){
- if(e.fi == fa) continue;
- dfs1(e.fi, x, cc);
- }
- }
- void Erase(int col){
- PII x = make_pair(-M[col]-no[col], col);
- S.erase(x);
- if(x.fi+ < ) S.insert({x.fi+, col});
- }
- int main()
- {
- cin>>n;
- for(int i = ; i < n; i++){
- int x, y, w;
- cin>>x>>y>>w;
- G[x].push_back({y, w});
- G[y].push_back({x, w});
- }
- int X;
- dfs0(, );
- for(int i = ; i <= n; i++) if(son[i] <= n/) X = i;
- dfs(X, X, );
- cout<<ANS*<<endl;
- int flag = , N = ;
- for(auto e : G[X]){
- ll[++N] = tot+;
- dfs1(e.fi, X, N);
- rr[N] = tot;
- S.insert({-*sz[e.fi], N});
- M[N] = no[N] = sz[e.fi];
- }
- f[X] = ++tot;
- Insert(, , n, tot, X);
- ll[++N] = tot;
- rr[N] = tot;
- col[X] = N;
- S.insert({, N});
- M[N] = no[N] = ;
- int l, r;
- for(int i = ; i <= n; i++){
- auto x = *S.begin();
- int rem = n-i+;
- if(col[i] != x.se){
- rem--;
- if(rem < -x.fi){
- l = ll[x.se], r = rr[x.se];
- int y = Query(, , n, l, r);
- ans[i] = y;
- Erase(x.se);
- M[x.se]--;
- Insert(, , n, f[y], 1e9);
- Erase(col[i]);
- no[col[i]]--;
- continue;
- }
- }
- l = ll[col[i]], r = rr[col[i]];
- int y = 1e9;
- if(l- > ) y = min(y, Query(, , n, , l-));
- if(r+ <= n) y = min(y, Query(, , n, r+, n));
- if(f[i] == n) y = min(i, y);
- Insert(, , n, f[y], 1e9);
- ans[i] = y;
- Erase(col[i]);
- no[col[i]]--;
- Erase(col[y]);
- M[col[y]]--;
- }
- for(int i = ; i <= n; i++) cout<<ans[i]<<" ";
- }
Codeforces Round #268 (Div. 1) 468D Tree(杜教题+树的重心+线段树+set)的更多相关文章
- Codeforces Round #268 (Div. 2) ABCD
CF469 Codeforces Round #268 (Div. 2) http://codeforces.com/contest/469 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...
- Codeforces Round #499 (Div. 1) F. Tree
Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...
- Codeforces Round #367 (Div. 2) A. Beru-taxi (水题)
Beru-taxi 题目链接: http://codeforces.com/contest/706/problem/A Description Vasiliy lives at point (a, b ...
- Codeforces Round #575 (Div. 3) 昨天的div3 补题
Codeforces Round #575 (Div. 3) 这个div3打的太差了,心态都崩了. B. Odd Sum Segments B 题我就想了很久,这个题目我是找的奇数的个数,因为奇数想分 ...
- 数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction
Tree Construction Problem's Link ------------------------------------------------------------------- ...
- 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 ...
- Codeforces Round #353 (Div. 2) D. Tree Construction 二叉搜索树
题目链接: http://codeforces.com/contest/675/problem/D 题意: 给你一系列点,叫你构造二叉搜索树,并且按输入顺序输出除根节点以外的所有节点的父亲. 题解: ...
- 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 ...
- Codeforces Round #353 (Div. 2) D. Tree Construction 模拟
D. Tree Construction 题目连接: http://www.codeforces.com/contest/675/problem/D Description During the pr ...
随机推荐
- 如何用 npm 同时执行两条监听命令
在日常项目中启动项目 需要启动项目可能需要不止一条命令 这就很麻烦 要开启两个bash 很麻烦 终于找到了比较好的解决方案 例如我的: npm run dev //启动项目项目 npm run jso ...
- 20.2 解析与序列化【JavaScript高级程序设计第三版】
JSON 之所以流行,拥有与JavaScript 类似的语法并不是全部原因.更重要的一个原因是,可以把JSON 数据结构解析为有用的JavaScript 对象.与XML 数据结构要解析成DOM 文档而 ...
- scala成长之路(3)隐式转换
不废话,先上例子:定义一个参数类型为String的函数: scala> def sayHello(name:String) = println("hello " + name ...
- Python爬虫爬取百度翻译之数据提取方法json
工具:Python 3.6.5.PyCharm开发工具.Windows 10 操作系统 说明:本例为实现输入中文翻译为英文的小程序,适合Python爬虫的初学者一起学习,感兴趣的可以做英文翻译为中文的 ...
- ABAP CDS ON HANA-(8)算術式
Arithmetic expression in CDS View Allowed Arithmetic operators in CDS view. CDS View- @AbapCatalog.s ...
- ABAP CDS ON HANA-(5)テーブル結合ビュー
JOINs in CDS View In ABAP CDS, Join between two data sources is allowed. Allowed joins are:- Inner J ...
- (转载)深入super,看Python如何解决钻石继承难题
1. Python的继承以及调用父类成员 python子类调用父类成员有2种方法,分别是普通方法和super方法 假设Base是基类 class Base(object): def __init_ ...
- Jquery操作select选项集合!
Query获取Select选择的Text和Value: 1. $("#select_id").change(function(){//code...}); //为Select添加事 ...
- PostgreSQL 10.0 压缩版的 pgAdmin 不能用的问题
PostgreSQL终于发布10.0正式版了!下载压缩版的更新了一下本机的版本,然后打开pgAdmin的时候总是报错“The application server could not be conta ...
- 不用找了,比较全的signalR例子已经为你准备好了(2)---JqGrid 服务端刷新方式-注释详细-DEMO源码下载
上次用客户端进行数据刷新的方式,和官方的Demo实现存在差异性,今天花了一点时间好好研究了一下后台时时刷新的方式.将写的代码重新update了一次,在这之前找过好多的资料,发现都没有找到好的例子,自己 ...