ICode9

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

CF1266F [*medium]

2021-01-09 09:34:49  阅读:253  来源: 互联网

标签:结点 medium int Max sum mxs mx1 CF1266F


看到其他题解里面全是什么 bfs 序上线段树啊,什么根号的奇怪东西啊,蒟蒻用了一个非常好写的 \(O(n)\) 做法(这里实现的时候用了 vector,所以比较慢),写篇题解来造福社会

目前在 cf 上是最短解


如果 \(k = 1\),答案是 \(\max(dep_i + 1)\)

考虑有 \(3\) 个点的情况:

通过放缩法可以证明(证明比较简单而繁琐略去)。考虑在这种情况下的链长(图中的 \(a, b, c\)):

  1. \(k\) 为奇数:有一个中心结点,旁边的链最多只有一个长为 \(\frac{k-1}{2}\) 的,其他都是 \(\frac{k + 1}{2}\)。
  2. \(k\) 为偶数:有一个中心结点,旁边的都是长为 \(\frac{k}{2}\) 的链。

但是这样会发现在样例 \(2\) 挂掉了。漏掉了下面的情况:

因此有了第 \(3\) 种情况 :在 \(k\) 为偶数的时候,有两个中心结点,旁边链长要求为 \(\frac{k}{2}\)。

在这 \(3\) 种情况下,我们发现一定满足 \(ans_x \ge ans_{x + 2}\)。

对于前两个情况,每一个结点我们记录以他为根时的子树深度,然后把这个深度进行排序。\(k\) 为偶数时第 \(i\) 大数 \(t\) 的则表示 \(ans_{2t} \ge i\) 。奇数稍微麻烦点,第 \(i\) 大数 \(t\) 的则表示 \(ans_{2t-1} \ge i\),如果不和排在前面的数相同,那么我们发现长度为 \(ans_{2t+1} \ge i\)(用这条链和之前面的几条链放在一起,就是长度为 \(t\) 和一堆 \(t + 1\))。这里都很显然。

第 \(3\) 种情况,显然可以把所有相邻的两个位置 \(A\), \(B\) 的子树深度数组给合并在一起,然后再按照第一种情况做就行了,可惜是 \(n^2\) 的。

考虑从后到前,对于这个子树深度数组扫描线,扫到 \(k\) 时更改每一个数的时候判一下和相邻结点的点的和 \(sum - 2\) (\(sum\) 会算到 \(B\) 做 \(A\) 子树和 \(A\) 做 \(B\) 子树的贡献,因此 \(sum\) 要减 \(2\))是否可以更新 \(ans_{k}\)。

这个可以套路地看作是计算父亲结点和子树结点的最大值,额外记录一下子树 \(sum\) 的最大值 \(mxs\),在修改一个结点的时候更新父亲结点的 \(mxs\),同时用 \(max(sum_{fa}, mxs)\) 来更新答案。

具体实现时,第 \(1\) 和第 \(2\) 种情况也可以把排序换成扫描线做到 \(O(n)\)

其余细节见代码。

#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
#define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
using namespace std;
const int N = 5e5 + 7;
void Max(int &x, int y) { if(x < y) x = y;  }
int n, deg[N], Fa[N], f1[N], f2[N], sum[N], mx1[N], mx2[N], up[N], mxs[N], las, u, v;
vector<int> G[N], e[N];
void dfs1(int x) {
	Max(f1[0], deg[x] + 1), mxs[x] = -1e9;
	for(int v : e[x]) if(v ^ Fa[x]) {
		Fa[v] = x, dfs1(v);
		if(mx1[v] + 1 > mx1[x]) mx2[x] = mx1[x], mx1[x] = mx1[v] + 1; else Max(mx2[x], mx1[v] + 1);
	}
}
void dfs2(int x) {
	if(x ^ 1) G[up[x]].push_back(x);
	for(int v : e[x]) if(v ^ Fa[x]) G[mx1[v] + 1].push_back(x);
	for(int v : e[x]) if(v ^ Fa[x]) up[v] = max(up[x], mx1[v] + 1 == mx1[x] ? mx2[x] : mx1[x]) + 1, dfs2(v);
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n, f1[n] = f2[n] = 1;
	L(i, 1, n - 1)  cin >> u >> v, deg[u] ++, deg[v] ++, e[u].push_back(v), e[v].push_back(u);
	dfs1(1), dfs2(1);
	R(i, n, 1) {
		las = 0;
		for(int t : G[i]) {
			sum[t] ++, Max(mxs[Fa[t]], sum[t]);
			Max(f2[i], sum[t] + mxs[t] - 2), Max(f2[i], sum[t] + sum[Fa[t]] - 2); // case 3
			Max(f2[i], sum[t]); // case 1
			Max(f1[i - 1], sum[t]); // case 2
			if(las != t) Max(f1[i], sum[t]); las = t; // case 2
		}
	}
	R(i, n, 1) Max(f1[i - 1], f1[i]), Max(f2[i - 1], f2[i]);
	L(i, 1, n) cout << (i % 2 ? f1[i / 2] : f2[i / 2]) << " ";
	cout << endl;
	return 0;
} 

祝大家学习愉快!

标签:结点,medium,int,Max,sum,mxs,mx1,CF1266F
来源: https://www.cnblogs.com/zkyJuruo/p/14254120.html

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

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

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

ICode9版权所有