时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一棵包含N个节点的无根树,节点编号1~N。其中每个节点都具有一个权值,第i个节点的权值是Ai。
小Hi希望你能找到树上的一条最长路径,满足沿着路径经过的节点的权值序列恰好构成等差数列。
输入
第一行包含一个整数N。
第二行包含N个整数A1, A2, ... AN。
以下N-1行,每行包含两个整数U和V,代表节点U和V之间有一条边相连。
对于50%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000, 0 ≤ Ai ≤ 100000, 1 ≤ U, V ≤ N
输出
最长等差数列路径的长度
样例输入
7
3 2 4 5 6 7 5
1 2
1 3
2 7
3 4
3 5
3 6
样例输出
4
思路:这道题我感觉很好。
总体思路是这样的,要找最长的等差数列,那么把d[i][j]当做是以i为节点,差为|d|的最长的长度,
那么这个节点两边就是要一边是+d,一边是-d,(自行想象)。
易错点就在于如果d=0时,那么就要考虑怎样找差值最大的两边的。这道题中用了f[i][0]和f[i][1]表示以i为节点的左端右端(不定)每次都从中找最长的进行保存,然后加起来。注意还要加上自身。
代码:
#include<iostream>
#include<string.h>
#include<map>
#include<vector>
#include<stdio.h>
using namespace std;
map<int,int>d[100100];
int vis[100100];
int w[100100];
int f[100100][2];
vector<int>G[100100];
int ans;
void dfs(int x)
{
vis[x]=1;
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(vis[v])
continue;
dfs(v);
if(w[x]==w[v])
{
if(f[x][0]<f[x][1])
f[x][0]=max(f[x][0],max(f[v][0],f[v][1])+1);
else
f[x][1]=max(f[x][1],max(f[v][0],f[v][1])+1);
ans=max(ans,f[x][0]+f[x][1]+1);
}
else{
d[x][w[x]-w[v]]=max(d[x][w[x]-w[v]],d[v][w[x]-w[v]]+1);//x节点,公差为w[x]-w[v]
ans=max(ans,d[x][w[x]-w[v]]+d[x][w[v]-w[x]]+1);
}
}
}
int main()
{
int n,u,v;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
G[i].clear();
}
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
ans=0;
dfs(1);
cout<<ans<<endl;
return 0;
}