树上的等差数列

题目描述

给定一棵包含 \(N\) 个节点的无根树,节点编号 \(1\to N\) 。其中每个节点都具有一个权值,第 \(i\) 个节点的权值是 \(A_i\) 。

小 \(Hi\) 希望你能找到树上的一条最长路径,满足沿着路径经过的节点的权值序列恰好构成等差数列。

输入格式

第一行包含一个整数 \(N\) 。

第二行包含 \(N\) 个整数 \(A_1, A_2, ... A_N\)。

以下 \(N-1\) 行,每行包含两个整数 \(U\) 和 \(V\) ,代表节点 \(U\) 和 \(V\) 之间有一条边相连。

输出格式

最长等差数列路径的长度

样例

样例输入

  1. 7
  2. 3 2 4 5 6 7 5
  3. 1 2
  4. 1 3
  5. 2 7
  6. 3 4
  7. 3 5
  8. 3 6

样例输出

  1. 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\) 的转移应该是:

\[ans = max(ans,f[x][0] + f[son[x]][0] + 2)
\]

因为此时 \(f[x][0]\) 存储的是其他儿子上最长链,所以需要加上当前儿子的最长链,因为我们的数组不保存自己,所以要加 \(2\) 。

其他情况就是直接更新 \(ans\) ,他的答案应该是 \(f[x][d] + f[x][-d] + 1\) ,因为他的父亲那里也可能会有链,公差为 \(-d\) 就是那个链,由于负数下标的问题,我们利用 \(map\) 来存储,然后轻松解决此题。

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<map>
  6. #define re register
  7. using namespace std;
  8. const int maxn = 1e5+10;
  9. map <int,int> mp[maxn];
  10. struct Node{
  11. int v,next;
  12. }e[maxn<<1];
  13. int w[maxn];
  14. int ans = 0;
  15. int head[maxn],tot;
  16. void Add(int x,int y){//建边
  17. e[++tot].v = y;
  18. e[tot].next = head[x];
  19. head[x] = tot;
  20. }
  21. inline int read(){//快读
  22. int s = 0,f = 1;
  23. char ch = getchar();
  24. while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
  25. while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
  26. return s * f;
  27. }
  28. inline void DP(int x,int fa){
  29. for(int i=head[x];i;i=e[i].next){
  30. int v = e[i].v;
  31. if(v == fa)continue;//避免死循环
  32. int d = w[v] - w[x];//计算公差
  33. DP(v,x);
  34. if(!d){//公差为0的情况
  35. ans = max(ans,mp[x][0] + mp[v][0] + 2);
  36. mp[x][0] = max(mp[x][0],mp[v][0] + 1);
  37. }
  38. else{//公差不为0
  39. mp[x][d] = max(mp[x][d],mp[v][d] + 1);
  40. ans = max(ans,mp[x][d] + mp[x][-d] + 1);
  41. }
  42. }
  43. }
  44. int main(){
  45. freopen("C.in","r",stdin);
  46. freopen("C.out","w",stdout);
  47. int n =read();
  48. for(re int i = 1;i<=n;++i){w[i]=read();}
  49. for(re int i = 1;i< n;++i){
  50. int x = read(),y = read();
  51. Add(x,y);
  52. Add(y,x);
  53. }
  54. DP(1,0);
  55. printf("%d\n",ans);
  56. }

树上的等差数列 [树形dp]的更多相关文章

  1. BZOJ_4033_[HAOI2015]树上染色_树形DP

    BZOJ_4033_[HAOI2015]树上染色_树形DP Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的 ...

  2. 2021.07.17 P3177 树上染色(树形DP)

    2021.07.17 P3177 树上染色(树形DP) [P3177 HAOI2015]树上染色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.dp思想是需要什么,维护 ...

  3. 【BZOJ4033】[HAOI2015] 树上染色(树形DP)

    点此看题面 大致题意: 给你一棵点数为N的带权树,要你在这棵树中选择K个点染成黑色,并将其他的N-K个点染成白色.要求你求出黑点两两之间的距离加上白点两两之间距离的和的最大值. 树形\(DP\) 这道 ...

  4. 洛谷P3177 [HAOI2015]树上染色(树形dp)

    题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之 ...

  5. BZOJ4033: [HAOI2015]树上染色(树形DP)

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3461  Solved: 1473[Submit][Stat ...

  6. bzoj 4033: [HAOI2015]树上染色【树形dp】

    准确的说应该叫树上分组背包?并不知道我写的这个叫啥 设计状态f[u][j]为在以点u为根的子树中有j个黑点,转移的时候另开一个数组,不能在原数组更新(因为会用到没更新时候的状态),方程式为g[j+k] ...

  7. BZOJ 4033[HAOI2015] 树上染色(树形DP)

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3188  Solved: 1366[Submit][Stat ...

  8. [HAOI2015]树上染色(树形dp)

    [HAOI2015]树上染色 题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所 ...

  9. 树上对抗搜索 - 树形dp

    Alice and Bob are going on a trip. Alice is a lazy girl who wants to minimize the total travelling d ...

随机推荐

  1. JavaScript经典实例

    1.指定范围生成随机数 function random(min, max) { if (arguments.length === 2) { return Math.floor(min + Math.r ...

  2. Java 并发队列 BlockingQueue

    BlockingQueue 开篇先介绍下 BlockingQueue 这个接口的规则,后面再看其实现. 首先,最基本的来说, BlockingQueue 是一个先进先出的队列(Queue),为什么说是 ...

  3. 1.pandas打开和读取文件

    最近在公司在弄数据分析相关的项目,数据分析就免不了要先对数据进行处理,也就自然避不开关于excel文档的初始化操作了. 一段时间之后,发现pandas更加符合我的项目要求,所以,将一些常规操作记录下来 ...

  4. LQB2013A01高斯日记

    诶,今天发生了点不是很开心的事.说实话挺影响心情的啊(谁遇见这种事不生气呢啊啊啊啊) 但是不能水更,还是得好好更新呀. 这个题居然直接用excel哈哈哈哈 那,,就这样吧!

  5. list 和 [ ] 的功能不相同

    对于一个对象: list(对象) 可以进行强制转换 [对象] 不能够进行强制转换,只是在外围加上 [ ] 列表推导式中相同   2020-05-06

  6. PHP abs() 函数

    实例 返回不同数的绝对值: <?phpecho(abs(6.7) . "<br>");echo(abs(-6.7) . "<br>" ...

  7. luogu P4775 [NOI2018]情报中心 线段树合并 虚树 树的直径trick

    LINK:情报中心 神题! 写了一下午 写到肚子疼. 调了一晚上 调到ex 用的是网上dalao的方法 跑的挺快的. 对于链的暴力 我不太会kk. 直接说正解吧: 分类讨论两种情况: 1 答案的两条链 ...

  8. Java异步之《我call(),Future在哪里》

    我们大家都知道,在 Java 中创建线程主要有三种方式: 继承 Thread 类: 实现 Runnable 接口: 实现 Callable 接口. 而后两者的区别在于 Callable 接口中的 ca ...

  9. Python创建一个爬虫项目===从零开始哟!想说的下次 要不要出一期关于pycharm与Python之间的合作

    当然,不用爬虫框架,也是可以的 比如说 beauitfulsoup xml http 就可以完美的得到一个爬虫的解决方案! 个人的意思是,新手或者刚入门的可以考虑以上的方式进行练习后 在使用框架 首先 ...

  10. 包管理Go module的使用

    我用 Golang 的 Web 框架 Iris 写项目时,发现下载依赖老是失败原因是被墙了(可以参考上一篇 https://www.cnblogs.com/ser0632/p/11374790.htm ...