法法塔是很喜欢写程序的。所以冒着就算码农屌丝一辈子的风险也大无畏地写着程序。
码农们为了表彰法法塔的坚持与执着,决定给法法塔颁布奖励,为了体现码农的屌丝气质,奖励也将由法法塔自己做出选择!
所有的奖励被组织成了一棵树的形态,每个点都有一个权值。法法塔首先选择一个子树,然后选择从该子树内的一个叶子节点到该子树的根的一条路径,将路径上节点的权值依次排成一个序列,求得这个序列的最长不下降子序列长度,这个长度就是他能得到的奖品数目。要求该子树的根必须被选择。
接下来就是法法塔进行选择的时间了。尽可能多地得到奖品是自然的。那么法法塔到底能够得到多少奖品呢?这是个很纠结的问题,他决定交给你来解决。对于每个子树,他都希望你能求出他首先选择了这个子树后,他能得到的最多的奖品数目。
第一行一个数n,描述树上节点的个数。
接下来一行n个数,描述树上每个点的父亲,点1为根,其父亲设为-1,其余每个点的父亲的标号都小于自己。
接下来一行n个数,表示树上每个点的权值。
一行n个数,第i个数表示法法塔选择了以第i个节点为根的子树后,他可以获得的最多的奖品个数。
输入1:
2
-1 1
1 1
输入2:
6
-1 1 2 1 2 4
4 3 4 3 6 2
输出1:
2 1
输出2:
3 1 1 2 1 1
n<=100000,每个数的权值都是1到n的正整数。
先考虑序列上面,求最长不下降子序列的方法,
其中就有一种方法就是用线段树。
于是就将这种方法扩展到树上,而且子树根节点是必须选到的。
因为每个点的权值都在n以内,
所以线段树上面的每一个叶子节点就表示当最后一个位置的值为x的时候最长可以有多少。
那么新加入一个就是在原有线段树上面,查询小于等于它的全部的最长一个,
然后当前这个,也就是根节点,必须选的。
如果每个节点只有只有一个儿子,那么就很方便了。
如果有多个儿子,也就是线段树合并。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return aabs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
struct node
{
int l,r,mx;
}tr[N*40];
int n,m,nxt[N],to[N],lst[N],x,y,tot;
int opl,opr,op,v[N],ans[N];
void ins(int x,int y)
{
nxt[++tot]=lst[x];
to[tot]=y;
lst[x]=tot;
}
void mix(int x,int y,int l,int r)
{
if(l==r)
{
tr[x].mx=max(tr[x].mx,tr[y].mx);
return;
}
int m=(l+r)>>1;
if(tr[y].l)
if(!tr[x].l)tr[x].l=tr[y].l;else mix(tr[x].l,tr[y].l,l,m);
if(tr[y].r)
if(!tr[x].r)tr[x].r=tr[y].r;else mix(tr[x].r,tr[y].r,m+1,r);
tr[x].mx=max(tr[tr[x].l].mx,tr[tr[x].r].mx);
}
void find(int x,int l,int r)
{
if(!x)return;
if(opl<=l && r<=opr)
{
op=max(op,tr[x].mx);
return;
}
int m=(l+r)>>1;
if(opl<=m)find(tr[x].l,l,m);
if(mtr[x].r,m+1,r);
}
void work(int x,int l,int r)
{
if(opl<=l && r<=opr)
{
tr[x].mx=max(tr[x].mx,op);
return;
}
int mid=(l+r)>>1;
if(opl<=mid)
{
if(!tr[x].l)tr[x].l=++m;
work(tr[x].l,l,mid);
}
if(midif(!tr[x].r)tr[x].r=++m;
work(tr[x].r,mid+1,r);
}
tr[x].mx=max(tr[tr[x].l].mx,tr[tr[x].r].mx);
}
void dfs(int x)
{
for(int i=lst[x];i;i=nxt[i])
{
dfs(to[i]);
mix(x,to[i],1,n);
}
op=0;opl=1;opr=v[x];
find(x,1,n);
opl=opr=v[x];
ans[x]=op=op+1;
work(x,1,n);
}
int main()
{
read(n);read(x);m=n;
for(int i=2;i<=n;i++)
read(x),ins(x,i);
for(int i=1;i<=n;i++)
read(v[i]);
dfs(1);
for(int i=1;i<=n;i++)
write(ans[i]),P(' ');
return 0;
}