Crazy Bobo
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 554 Accepted Submission(s): 168
Total Submission(s): 554 Accepted Submission(s): 168
Problem Description
Bobo has a tree,whose vertices are conveniently labeled by 1,2,...,n.Each node has a weight
wi
. All the weights are distrinct.
A set with m nodes v1,v2,...,vm is a Bobo Set if:
- The subgraph of his tree induced by this set is connected.
- After we sort these nodes in set by their weights in ascending order,we get u1,u2,...,um ,(that is, wui<wui+1 for i from 1 to m-1).For any node x in the path from ui to ui+1 (excluding ui and ui+1 ),should satisfy wx<wui .
Your task is to find the maximum size of Bobo Set in a given tree.
A set with m nodes v1,v2,...,vm is a Bobo Set if:
- The subgraph of his tree induced by this set is connected.
- After we sort these nodes in set by their weights in ascending order,we get u1,u2,...,um ,(that is, wui<wui+1 for i from 1 to m-1).For any node x in the path from ui to ui+1 (excluding ui and ui+1 ),should satisfy wx<wui .
Your task is to find the maximum size of Bobo Set in a given tree.
Input
The input consists of several tests. For each tests:
The first line contains a integer n ( 1≤n≤500000 ). Then following a line contains n integers w1,w2,...,wn ( 1≤wi≤109 ,all the wi is distrinct).Each of the following n-1 lines contain 2 integers ai and bi ,denoting an edge between vertices ai and bi ( 1≤ai,bi≤n ).
The sum of n is not bigger than 800000.
The first line contains a integer n ( 1≤n≤500000 ). Then following a line contains n integers w1,w2,...,wn ( 1≤wi≤109 ,all the wi is distrinct).Each of the following n-1 lines contain 2 integers ai and bi ,denoting an edge between vertices ai and bi ( 1≤ai,bi≤n ).
The sum of n is not bigger than 800000.
Output
For each test output one line contains a integer,denoting the maximum size of Bobo Set.
Sample Input
7 3 30 350 100 200 300 400 1 2 2 3 3 4 4 5 5 6 6 7
Sample Output
5
题意:给出一棵树,现在要你在树上找出一条结点最多的子树,这棵子树满足: 在对树上的每个节点按权值大小排序后,排序后相邻的点必须满足从这个结点到另一个结点途径的所有结点的权值(不包括起点和终点)都小于这两个结点的权值。
比如例1
1-2-3-4-5-6-7
权值依次为 3 30 350 100 200 300 400
现在找到了最长的这样一棵子树 3-4-5-6-7
然后进行权值由小到大排序得到 4 5 6 3 7 权值依次为 100 200 300 350 400
- 3与4相邻 经过原树路径 3-4
- 4与5相邻 经过原树路径 4-5
- 5与6相邻 经过原树路径 5-6
- 6与3相邻 经过原树路径 3-4-5-6 权值依次为 350 100 200 300 4和5权值小于6和3(起点终点)的权值
- 3与7相邻 经过原树路径 3-4-5-6-7 权值依次为 350 100 200 300 400 4和5,6权值小于7和3(起点终点)的权值
那么对于排序后假设有 u1 u2 u3 u4 u5 结点 按权值升序
u1和u2一定是相邻的 u1一定最小
对于u3 可以连在u1上,也可以连在u2上(此时一定满足条件)
对于u4 可以连在任意以u1为根的叶子和结点。
u5同u4
那么此时一棵最长子树就建好了
接下来思路就很明确了,以小权值结点作为根结点,建成一棵每个结点有方向树,找出连接每个根结点下还有多少个结点即是答案。
但是很遗憾,这样建成一棵树之后如果进行树的遍历,由于数据过大,如果操作不当很容易爆栈!
那么我们应该想想别的思路,结点+有向边+不能递归遍历,如果把有向边改成每个点的入度和出度,然后直接拓扑排序记录权值问题不就迎刃而解了吗!?
<span style="font-size:18px;">#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 500005
int in[maxn];
int fir[maxn];
int u[maxn],v[maxn],w[maxn],nex[maxn];
int ans[maxn];
int que[maxn];
int e_max;
int n;
void init()
{
e_max=0;
memset(fir,-1,sizeof fir);
memset(ans,0,sizeof ans);
memset(in,0,sizeof in);
}
void add_edge(int s,int t)
{
int e=e_max++;
u[e]=s;
v[e]=t;
nex[e]=fir[u[e]];
fir[u[e]]=e;
}
int toposort()
{
int temp=0;
int f=0,r=-1;
for(int i=1;i<=n;i++)
if(in[i]==0) que[++r]=i;
while(f<=r)
{
int k=que[f++];
in[k]--;
for(int i=fir[k];~i;i=nex[i])
{
int e=v[i];
in[e]--;
ans[e]+=ans[k]+1;
if(in[e]==0)
que[++r]=e;
}
}
for(int i=1;i<=n;i++)
temp=max(temp,ans[i]);
return temp+1;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1; i<=n; i++)
{
scanf("%d",&w[i]);
}
for(int i=0; i<n-1; i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(w[a]<w[b]) swap(a,b);
add_edge(a,b);
in[b]++;
}
printf("%d\n",toposort());
}
return 0;
}
</span>