[ 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;
}

  

时间: 2024-10-22 04:48:48

[ NOIP ] SJZEZ五月小测笔记的相关文章

七月算法--12月机器学习在线班-第五次课笔记—回归

七月算法--12月机器学习在线班-第五次课笔记—回归 七月算法(julyedu.com)12月机器学习在线班学习笔记 http://www.julyedu.com

C#基础知识篇(五)-----------C#笔记

一.值类型和引用类型 1>值类型和引用类型将我们学过的数据类型划分成了两部分. 划分的依据是不同类型的数据在内存中(堆栈)存储的结构不同. 2>值类型:所有的数值类型:long int short byte ulong uint ushort sbyte decimal duoble float char bool 枚举 结构 3>引用类型:string,arry(数组),类(class) 4>不管是值类型还是引用类型赋值都是将数据copy一份将副本赋给变量,不同的是值类型拷贝的是

Linux第五周上课笔记(1),rpm软件安装,yum源,yum仓库

第五周上课笔记 一.应用软件的安装 1.认识软件:|libmp3lame0|-3.99.3-23|.el7|.x86_64|.rpm 软件名     软件版本   适用系统 64位  红帽适用软件 2.如何安装软件 1.rpm rpm      -vih    name.rpm      安装,-v:显示过程,-h:指定加密方式为哈希加密 -e      name          卸载 -q      name          查询软件生成文件 -qlp  name.rpm        查

七月算法-12月机器学习在线班--第十五次课笔记—主题模型

七月算法-12月机器学习--第十五次课笔记—主题模型 七月算法(julyedu.com)12月机器学习在线班学习笔记http://www.julyedu.com 复习的知识: 1.,Γ函数 是阶乘在实数上的推广,即实数的阶乘 2,Beta分布 Beta分布的概率密度: 其中系数B为: 两者的关系 1,朴素贝叶斯分析 朴素贝叶斯没有分析语意,无法解决语料中一词多义和多词一义的问题,更像是词法的分析,可以 一, 1个词可能被映射到多个主题中——一词多义 二,多个词可能被映射到某个主题的概率很高——多

【阅读笔记】计算机网络 第五版 阅读笔记(持续更新)

计算机网络 第五版阅读笔记 第一章 概述 1.因特网的组成 边缘部分:由所有连接在因特网上的主机组成 核心部分:由大量网络和连接这些网络的路由器组成 2.计算机之间的通信方式 客户服务器端方式(C/S模式):客户端是服务请求方,服务器端是服务提供方 对等方式(P2P模式):平等,对等连接通信,每一个主机既是客户又是服务器. 3.电路交换,分组交换和报文交换 3.1 电路交换:建立连接(占用通信资源)->通话(一直占用)->释放连接(释放通信资源). 优点:在通话的全部时间内,通话的两个用户始终

Android深度探索——第五章读书笔记及心得

搭建S3C6410开发板的测试环境 ——第五章读书笔记及心得 通过本章的学习学会了如何在开发板上安装Android.开发板是学习和开发嵌入式技术的主要硬件设备,想要顺利的通过linux驱动访问硬件,是不能在PC板上模拟的,需要在卡发板上进行调试和测试.其相对于手机更适合与对程序进行测试,尤其是对底层linux程序进行测试.还了解了S3C6410开发板的基本信息.知道了如何安装串口调试工具以及烧写Android系统.知道了如何配置有线网络. S3C6410是一款低功耗.高性价比的精简指令集计算机处

C++ Primer 第五版学习笔记

<C++ Primer>第五版中文版学习笔记 ? C++ Primer 第五版学习笔记

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器

C++ Primer(第五版)学习笔记_9_标准模板库_multimap多重映照容器 多重映照容器multimap与map结构基本相同,但由于重复键值存在,所以multimap的元素插入.删除.查找都与map的方法不相同. 1.multimap对象创建.元素插入 插入元素时,需要使用insert()方法和类似pair<string,double>("Jack", 300.5)的元素结构.可以看到,重复的元素是按照插入的先后顺序排序的. #include <iostre

C++ Primer(第五版)学习笔记_5_标准模板库string(2)

C++ Primer(第五版)学习笔记_5_标准模板库string(2) 10.搜索string对象的元素或子串 采用find()方法可查找字符串中的第一个字符元素(char, 用单引号界定)或者子串(用双引号界定):如果查到,则返回下标值(从0开始计数),如果查不到,则返回一个很大的数string:npos(即:4294967295). #include <iostream> #include <stdio.h> #include <string> using nam