jzoj3338. 【NOI2013模拟】法法塔的奖励

Description

法法塔是很喜欢写程序的。所以冒着就算码农屌丝一辈子的风险也大无畏地写着程序。
码农们为了表彰法法塔的坚持与执着,决定给法法塔颁布奖励,为了体现码农的屌丝气质,奖励也将由法法塔自己做出选择!
所有的奖励被组织成了一棵树的形态,每个点都有一个权值。法法塔首先选择一个子树,然后选择从该子树内的一个叶子节点到该子树的根的一条路径,将路径上节点的权值依次排成一个序列,求得这个序列的最长不下降子序列长度,这个长度就是他能得到的奖品数目。要求该子树的根必须被选择。
接下来就是法法塔进行选择的时间了。尽可能多地得到奖品是自然的。那么法法塔到底能够得到多少奖品呢?这是个很纠结的问题,他决定交给你来解决。对于每个子树,他都希望你能求出他首先选择了这个子树后,他能得到的最多的奖品数目。

Input

第一行一个数n,描述树上节点的个数。
接下来一行n个数,描述树上每个点的父亲,点1为根,其父亲设为-1,其余每个点的父亲的标号都小于自己。
接下来一行n个数,表示树上每个点的权值。

Output

一行n个数,第i个数表示法法塔选择了以第i个节点为根的子树后,他可以获得的最多的奖品个数。

Sample Input

输入1:
2
-1 1
1 1

输入2:
6
-1 1 2 1 2 4
4 3 4 3 6 2

Sample Output

输出1:
2 1

输出2:
3 1 1 2 1 1

Data Constraint

n<=100000,每个数的权值都是1到n的正整数。

题解

话说这题解法也很多啊。
100%
多种解法,分点答题。

cdq分治
由于这道题有三个限制,是一个三维偏序的问题。
三个限制分别是:(dfn是在进栈就加入,DFN是出栈加入)
dfn序里面x在y右边。
DFN序里面x在y左边。
value里,x小于等于y。
这样才能把x转移到y。
(其实就是二维偏序)
具体实现我不会。

树套树
我们发现,上面的dfn序是很有用的。
每次可以发现,第x的节点可以由dfn序中的一段的f得来。
而这一段就是表示x的子树。
其次,我们发现,x节点只能从value不比他大的节点转移而来.
有一个套路——我们设dfn序为坐标系中的y轴,value为x轴。
那么我们就可以利用树套树来进行维护。
我们套一个树状数组来维护x轴(因为是求1~value,所以可以利用树状数组)
然后再在树状数组中套线段树维护y轴即可。
当然,要动态开点(这个pascal选手量力而行,因为setlength贼慢,比赛我打直接T成傻子)

扫描线
这个其实我们利用树套树的套路,建立一个坐标系(矩阵)。
然后我们发现,每次选答案都是一个子矩阵的答案。
直接利用扫描线即可。

线段树合并
我们发现上面的方法都太神仙了。
我们回归简单的想法——
由于是求最长不下降子序列,一个原始做法就是建一颗权值线段树。
然鹅现在我们发现,在树上做这个东西的时候,我们可能会有很多的线段树要更新。
那么我们考虑线段树合并!
先把每个节点都建一颗线段树。
每次我们把一个点的儿子节点的线段树都合并起来,再更新当前节点的答案。
依次合并上去即可。
当然,setlength也是量力而行,我™用了就T78.

标程

uses math;
type
        new=record
                l,r,ans:longint;
        end;
var
        i,j,k,l,n,m,tot,num,ans,gs:longint;
        fa,val,id,en,ni,answer:array[1..100000] of longint;
        son:array[1..100000] of boolean;
        tov,next,last:array[1..200000] of longint;
        tree:array[1..10000000] of new;
procedure insert(x,y:longint);
begin
        inc(tot);
        tov[tot]:=y;
        next[tot]:=last[x];
        last[x]:=tot;
end;

procedure mix(op,oq,l,r:longint);
var
        m,xx,yy:longint;
begin
        if (l=r) then
        begin
                tree[op].ans:=max(tree[op].ans,tree[oq].ans);
        end
        else
        begin
                m:=(l+r) shr 1;
                xx:=tree[oq].l;yy:=tree[oq].r;
                if tree[oq].l>0 then
                begin
                        if tree[op].l=0 then tree[op].l:=tree[oq].l
                        else mix(tree[op].l,tree[oq].l,l,m);
                end;
                if tree[oq].r>0 then
                begin
                        if tree[op].r=0 then tree[op].r:=tree[oq].r
                        else mix(tree[op].r,tree[oq].r,m+1,r);
                end;
                tree[op].ans:=max(tree[tree[op].l].ans,tree[tree[op].r].ans);
        end;
end;
procedure change(x,l,r,val,gb:longint);
var
        m:longint;
begin
        if (l=r) then
        begin
                tree[x].ans:=gb;
        end
        else
        begin
                m:=(l+r)shr 1;
                if val<=m then
                begin
                        if tree[x].l=0 then
                        begin
                                inc(gs);
                                //setlength(tree,gs+1);
                                tree[x].l:=gs;
                        end;
                        change(tree[x].l,l,m,val,gb)
                end
                else
                if val>m then
                begin
                        if tree[x].r=0 then
                        begin
                                inc(gs);
                                //setlength(tree,gs+1);
                                tree[x].r:=gs;
                        end;
                        change(tree[x].r,m+1,r,val,gb);
                end;
                tree[x].ans:=0;
                if tree[x].l>0 then tree[x].ans:=max(tree[x].ans,tree[tree[x].l].ans);
                if tree[x].r>0 then tree[x].ans:=max(tree[x].ans,tree[tree[x].r].ans);
        end;
end;
procedure get(x,l,r,st,en:longint);
var
        m:longint;
begin
        if (l=st)and(r=en) then
        begin
                ans:=max(ans,tree[x].ans)
        end
        else
        begin
                m:=(l+r)shr 1;
                if (en<=m) and (tree[x].l>0) then get(tree[x].l,l,m,st,en)
                else if (st>m) and (tree[x].r>0) then get(tree[x].r,m+1,r,st,en)
                else
                begin
                        if tree[x].l>0 then
                        get(tree[x].l,l,m,st,m);
                        if tree[x].r>0 then
                        get(tree[x].r,m+1,r,m+1,en);
                end;
        end;
end;

procedure dfs(x:longint);
var
        i,j:longint;
        bz:boolean;
begin
        i:=last[x];
        bz:=true;
        while i>0 do
        begin
                if tov[i]<>fa[x] then
                begin
                        bz:=false;
                        dfs(tov[i]);
                        mix(x,tov[i],1,n);
                end;
                i:=next[i];
        end;
        if bz then
        begin
                answer[x]:=1;
                change(x,1,n,val[x],1);
        end
        else
        begin
                ans:=0;
                get(x,1,n,1,val[x]);
                answer[x]:=ans+1;
                change(x,1,n,val[x],ans+1);
        end;
end;
begin
        //assign(input,'0data.in');reset(input);
        //assign(output,'0data.out');rewrite(output);
        readln(n);
        for i:=1 to n do read(fa[i]);
        fa[1]:=0;
        for i:=2 to n do
        begin
                insert(i,fa[i]);insert(fa[i],i);
        end;
        for i:=1 to n do read(val[i]);
        //setlength(tree,n+1);
        gs:=n;
        dfs(1);
        for i:=1 to n do write(answer[i],' ');
        writeln;
end.
end.


你可能感兴趣的:(数位DP,线段树&树状数组&权值线段树)