树上的等差数列 [树形dp]
树上的等差数列
题目描述
给定一棵包含 \(N\) 个节点的无根树,节点编号 \(1\to N\) 。其中每个节点都具有一个权值,第 \(i\) 个节点的权值是 \(A_i\) 。
小 \(Hi\) 希望你能找到树上的一条最长路径,满足沿着路径经过的节点的权值序列恰好构成等差数列。
输入格式
第一行包含一个整数 \(N\) 。
第二行包含 \(N\) 个整数 \(A_1, A_2, ... A_N\)。
以下 \(N-1\) 行,每行包含两个整数 \(U\) 和 \(V\) ,代表节点 \(U\) 和 \(V\) 之间有一条边相连。
输出格式
最长等差数列路径的长度
样例
样例输入
7
3 2 4 5 6 7 5
1 2
1 3
2 7
3 4
3 5
3 6
样例输出
4
数据范围与提示
对于 \(50\%\) 的数据,\(1 \leqslant N \leqslant 1000\)
对于 \(100\%\) 的数据,\(1 \leqslant N \leqslant 100000, 0 \leqslant A_i \leqslant 100000, 1 \leqslant U, V \leqslant N\)
分析
树形 \(dp\) 好题。
因为要求的是最长的等差序列,根节点不同,答案也可能不同,所以 \(dp\) 的状态转移就定义为 \(f[i][j]\) 表示 \(i\) 节点为根,公差为 \(j\) 时的最长的等差数列,不包括自己。那么我们就可以愉快的 \(dfs\) 来进行转移了。
我们记录一下他自己和他的父亲,避免出现死循环,每一次先 \(dfs\) 到儿子,递归上来,然后就处理出来了公差为 \(\Delta\) 的以儿子为根的所有长度,这时候我们只需要判断一下此时的 \(\Delta\) 值是否为 \(0\)。如果是,那么 \(ans\) 的转移应该是:
\]
因为此时 \(f[x][0]\) 存储的是其他儿子上最长链,所以需要加上当前儿子的最长链,因为我们的数组不保存自己,所以要加 \(2\) 。
其他情况就是直接更新 \(ans\) ,他的答案应该是 \(f[x][d] + f[x][-d] + 1\) ,因为他的父亲那里也可能会有链,公差为 \(-d\) 就是那个链,由于负数下标的问题,我们利用 \(map\) 来存储,然后轻松解决此题。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#define re register
using namespace std;
const int maxn = 1e5+10;
map <int,int> mp[maxn];
struct Node{
	int v,next;
}e[maxn<<1];
int w[maxn];
int ans = 0;
int head[maxn],tot;
void Add(int x,int y){//建边
	e[++tot].v = y;
	e[tot].next = head[x];
	head[x] = tot;
}
inline int read(){//快读
	int s = 0,f = 1;
	char ch = getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s * f;
}
inline void DP(int x,int fa){
	for(int i=head[x];i;i=e[i].next){
		int v = e[i].v;
		if(v == fa)continue;//避免死循环
		int d = w[v] - w[x];//计算公差
		DP(v,x);
		if(!d){//公差为0的情况
			ans = max(ans,mp[x][0] + mp[v][0] + 2);
			mp[x][0] = max(mp[x][0],mp[v][0] + 1);
		}
		else{//公差不为0
			mp[x][d] = max(mp[x][d],mp[v][d] + 1);
			ans = max(ans,mp[x][d] + mp[x][-d] + 1);
		}
	}
}
int main(){
	freopen("C.in","r",stdin);
	freopen("C.out","w",stdout);
	int n =read();
	for(re int i = 1;i<=n;++i){w[i]=read();}
	for(re int i = 1;i< n;++i){
		int x = read(),y = read();
		Add(x,y);
		Add(y,x);
	}
	DP(1,0);
	printf("%d\n",ans);
}
												
											树上的等差数列 [树形dp]的更多相关文章
- BZOJ_4033_[HAOI2015]树上染色_树形DP
		
BZOJ_4033_[HAOI2015]树上染色_树形DP Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的 ...
 - 2021.07.17 P3177 树上染色(树形DP)
		
2021.07.17 P3177 树上染色(树形DP) [P3177 HAOI2015]树上染色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.dp思想是需要什么,维护 ...
 - 【BZOJ4033】[HAOI2015] 树上染色(树形DP)
		
点此看题面 大致题意: 给你一棵点数为N的带权树,要你在这棵树中选择K个点染成黑色,并将其他的N-K个点染成白色.要求你求出黑点两两之间的距离加上白点两两之间距离的和的最大值. 树形\(DP\) 这道 ...
 - 洛谷P3177 [HAOI2015]树上染色(树形dp)
		
题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之 ...
 - BZOJ4033: [HAOI2015]树上染色(树形DP)
		
4033: [HAOI2015]树上染色 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3461 Solved: 1473[Submit][Stat ...
 - bzoj 4033: [HAOI2015]树上染色【树形dp】
		
准确的说应该叫树上分组背包?并不知道我写的这个叫啥 设计状态f[u][j]为在以点u为根的子树中有j个黑点,转移的时候另开一个数组,不能在原数组更新(因为会用到没更新时候的状态),方程式为g[j+k] ...
 - BZOJ 4033[HAOI2015] 树上染色(树形DP)
		
4033: [HAOI2015]树上染色 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3188 Solved: 1366[Submit][Stat ...
 - [HAOI2015]树上染色(树形dp)
		
[HAOI2015]树上染色 题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所 ...
 - 树上对抗搜索 - 树形dp
		
Alice and Bob are going on a trip. Alice is a lazy girl who wants to minimize the total travelling d ...
 
随机推荐
- react : umi 引入 antd 踩坑
			
首先要明确一个问题. 不管是 antd 还是 dva 还是别的什么东西,他们都是 umi 的插件——只要这个项目是使用 umi 脚手架生成的. 所以第一步应该是 .umirc.js (config.j ...
 - 深入理解JVM(二)垃圾收集器
			
GC三问: 哪些内存需要回收? 什么时候回收? 如何回收? 程序计数器.虚拟机栈.本地方法栈随线程而生,随线程而灭,栈帧的内存分配在类结构确定下来就已知,在方法结束或者线程结束时就会回收.所以垃圾回收 ...
 - Markdown画图(mermaid)学习
			
简介 目前博客园支持mermaid的graph,subgraph,sequenceDiagram,gantt,classDiagram mermaid(美人鱼), 是一个类似markdown,用文本语 ...
 - Python编程入门(第3版)|百度网盘免费下载|零基础入门学习资料
			
百度网盘免费下载:Python编程入门(第3版) 提取码:rsd7 目录 · · · · · · 第1章 编程简介 11.1 Python语言 21.2 Python适合用于做什么 31.3 程序员 ...
 - kafka笔记——入门介绍
			
中文文档 目录 kafka的优势 首先几个概念 kafka的四大核心API kafka的基本术语 主题和日志(Topic和Log) 每个分区都是一个顺序的,不可变的队列,并且可以持续的添加,分区中的每 ...
 - 关于RecyclerView(二)设置EmptyView
			
首先重写一个RecyclerView类 package com.onepilltest.others; import android.content.Context; import android.s ...
 - CSS样式基础2
			
CSS: 一.常用样式:字体,颜色,背景 二.布局:浮动 定位 标签特性 三.标签盒子模型: 边距 边框 四.动画:旋转 渐变 注意:子标签会继承父标签的样式但不是所有的样式都会被继承. 1.1 ...
 - java实现经典坦克大战及源代码下载
			
坦克大战源码 (点击即可下载) 链接:https://pan.baidu.com/s/1m9aVheaquwxGKjYQrb72AA 提取码:j8dr see you ! 觉得有用的话点个赞再走
 - PHP array_walk_recursive() 函数
			
实例 对数组中的每个元素应用用户自定义函数: <?phpfunction myfunction($value,$key){echo "The key $key has the valu ...
 - PHP stristr() 函数
			
实例 查找 "world" 在 "Hello world!" 中的第一次出现,并返回字符串的剩余部分: <?php高佣联盟 www.cgewang.com ...