[Feyat Cup 1.0][JZOJ3338]法法塔的奖励

来源:互联网 发布:神人鉴知 编辑:程序博客网 时间:2024/06/05 21:07

题目大意

给定一棵n个节点的树,每个点有一个权值vi
对于以x为根的子树,我们要从中找出一条从叶子节点到x的路径,将所有权值按顺序排列,求其最长不下降子序列(x一定要选),所有这种路径中最长的最长不下降子序列长度即为该子树答案。
求以每一个节点为根的子树的答案。

1vin105


题目分析

显然我们需要递归处理子树,合并所有儿子子树的信息,更新当前子树答案。
考虑使用什么数据结构维护最长不下降子序列,我们可以用权值线段树、平衡树等等。
然后合并所有儿子上的数据结构,更新答案即可。
我使用的是权值线段树,合并时直接合并即可。至于线段树合并为什么是O(nlog2n)的我也不会证。
具体细节见代码实现。


代码实现

#include <iostream>#include <cstdio>#include <cctype>using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (!isdigit(ch))    {        if (ch=='-')            f=-1;        ch=getchar();    }    while (isdigit(ch))    {        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}int buf[20];void write(int x){    if (x<0)        putchar('-'),x=-x;    buf[0]=0;    while (x)    {        buf[++buf[0]]=x%10;        x/=10;    }    if (!buf[0])        buf[++buf[0]]=0;    while (buf[0])        putchar(buf[buf[0]--]+'0');}const int N=100050;const int L=100000;const int S=N*20;struct segment_tree{    int v[S],son[S][2],root[N];    int tot;    int merge(int rt1,int rt2,int l,int r)    {        if (!(1ll*rt1*rt2))            return rt1+rt2;        v[rt1]=max(v[rt1],v[rt2]);        if (l==r)            return rt1;        int mid=l+r>>1;        son[rt1][0]=merge(son[rt1][0],son[rt2][0],l,mid);        son[rt1][1]=merge(son[rt1][1],son[rt2][1],mid+1,r);        return rt1;    }    int query(int rt,int st,int en,int l,int r)    {        if (!rt)            return 0;        if (l==st&&r==en)            return v[rt];        int mid=l+r>>1;        if (en<=mid)            return query(son[rt][0],st,en,l,mid);        else            if (mid+1<=st)                return query(son[rt][1],st,en,mid+1,r);            else                return max(query(son[rt][0],st,mid,l,mid),query(son[rt][1],mid+1,en,mid+1,r));    }    int change(int rt,int y,int l,int r,int edit)    {        if (!rt)            rt=++tot;        if (l==r)        {            v[rt]=max(edit,v[rt]);            return rt;        }        int mid=l+r>>1;        if (y<=mid)            son[rt][0]=change(son[rt][0],y,l,mid,edit);        else            son[rt][1]=change(son[rt][1],y,mid+1,r,edit);        v[rt]=max(v[son[rt][0]],v[son[rt][1]]);        return rt;    }}t;int ans[N],fa[N],last[N],next[N],tov[N],val[N];int tot,n;void insert(int x,int y){    tov[++tot]=y;    next[tot]=last[x];    last[x]=tot;}void dfs(int x){    int i=last[x],y,rt=0;    while (i)    {        y=tov[i];        dfs(y);        rt=t.merge(rt,t.root[y],1,L);        i=next[i];    }    ans[x]=t.query(rt,1,val[x],1,L)+1;    t.root[x]=t.change(rt,val[x],1,L,ans[x]);}int main(){    freopen("reward.in","r",stdin);    freopen("reward.out","w",stdout);    n=read();    read();    for (int i=2;i<=n;i++)        fa[i]=read(),insert(fa[i],i);    for (int i=1;i<=n;i++)        val[i]=read();    dfs(1);    for (int i=1;i<=n;i++)        write(ans[i]),putchar(i!=n?' ':'\n');    fclose(stdin);    fclose(stdout);    return 0;}
0 0
原创粉丝点击