[ NOIP ] SJZEZ五月小测笔记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ NOIP ] SJZEZ五月小测笔记相关的知识,希望对你有一定的参考价值。

                 树

 

【问题描述】
  读入一颗 n个点的带权树,求
  1. 直径长度。(距离最远的两点) 直径长度。(距离最远的两点)
  2. 若删去任意一个点,原树会分裂成些连通块。求数最多的大小的最值。
  3. 读入 Q个询问,每包括 (x,y) (x,y) ,表示查询从 ,表示查询从 x到 y路径上点权的最大值。
【输入格式】
  输入文件 tree.in。
  第一行两个整数 n,Q 。
  第二行 n个整数 v[i] v[i] ,代表点权。
  接下来 n-1行,每两个数 u,v 。代表树中有一条 (u,v) (u,v)的边。
  接下来 Q行,每两个数 x,y 。
  代表一次询问

【输出格式】
  输出文件 tree.outtree.out tree.out tree.out 。
  第一行输出直径长度。
  第二行输出删去一个点后数最多的连通块大小值。
  接下来 Q行,表示 Q次询问的答案。
【样例输入】

5 2
1 2 3 4 5
1 2
2 4
4 5
2 3
1 4
3 5


【样例输出】

3
2
4
5


【数据规模和约定】
  对于 30% 的数据, 1≤??,??≤1000。
  对于 100% 的数据, 1≤??,??≤100000,0≤??[??]≤100000。

 

-----------------------------------------------------------------

一、树形dp

  dfs搜索,对于每一个子树,p表示当前字树的根,x表示当前指向的孩子,len[p]表示p到叶子的最长距离,maxlen表示最长直径,则:

  为了避免出现当前孩子连接一条最长距离,且此距离异常更新了maxlen,我们必须先用没有更新len[x]的len[p]来更新maxlen,

  这时的len[p]是孩子1...x-1中的最长距离,所以1...x-1中的非最长距离不会影响maxlen,所以如果len[x]更新了len[p],则上一步的maxlen更新

  已经包括了len[x]这条路径。所以:

    maxlen = max{ maxlen, len[p] + len[x] + 1 }

    len[p] = max{ len[p], len[x] + 1 }

二、枚举

三、倍增法更新树上的一段路径的点权最大值,标准倍增法

 

code:

 

//Kvar_ispw17
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x7f7f7f7f;

int n, q, w[maxn][21], fa[maxn][21], dep[maxn], siz[maxn], len[maxn], max_len, mx[maxn];
vector<int> v[maxn];

void add(int a, int b) { v[a].push_back(b);}

void dfs(int p) {
	dep[p] = dep[fa[p][0]] + 1;
	siz[p] = 1;
	vector<int>::iterator it;
	for(it = v[p].begin(); it != v[p].end(); it++) {
		int x = *it;
		if(x != fa[p][0]) {
			fa[x][0] = p;
			dfs(x);
			siz[p] += siz[x];
			mx[p] = max(mx[p], siz[x]);
			max_len = max(max_len, len[p] + len[x] + 1);
			len[p] = max(len[p], len[x] + 1);
		}
	}
	return;
}

int ask(int x, int y) {
	if(dep[y] > dep[x]) swap(x, y);
	int ans = w[x][0];
	for(int j = 20; j >= 0; j--) {
		if(dep[fa[x][j]] >= dep[y]) {
			ans = max(ans, w[x][j]);
			x = fa[x][j];
		}
	}
	if(x == y) return max(ans, w[x][0]);
	for(int j = 20; j >= 0; j--) {
		if(fa[x][j] != fa[y][j]) {
			ans = max(ans, max(w[x][j], w[y][j]));
			x = fa[x][j], y = fa[y][j];
		}
	}
	return max(ans, max(w[x][1], w[y][1]));
}

int main() {
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++) scanf("%d", &w[i][0]);
	for(int i = 1; i < n; i++) {
		int a, b;
		scanf("%d%d", &a, &b);
		add(a,b);
		add(b,a);
	}
	dfs(1);
	printf("%d\n", max_len);
	int m = n;
	for(int i = 1; i <= n; i++) m = min(m, max(mx[i], n - siz[i]));
	printf("%d\n", m);
	for(int j = 0; j <= 20; j++) {
		for(int i = 1; i <= n; i++) {
			if(fa[i][j]) {
				fa[i][j + 1] = fa[fa[i][j]][j];
				w[i][j + 1] = max(w[i][j], w[fa[i][j]][j]);
			}
		}
	}
	while(q--) {
		int a, b;
		scanf("%d%d", &a, &b);
		printf("%d\n", ask(a, b));
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

 

  

 

以上是关于[ NOIP ] SJZEZ五月小测笔记的主要内容,如果未能解决你的问题,请参考以下文章

noip2017普及 luogu3954 成绩

HEOI2017 酱油记

Java小测代码及截图

20180630小测

20180625小测

20180222小测