• 【JZOJ4746】【NOIP2016提高A组模拟9.3】树塔狂想曲


    题目描述

    相信大家都在长训班学过树塔问题,题目很简单求最大化一个三角形数塔从上往下走的路径和。走的规则是:(i,j)号点只能走向(i+1,j)或者(i+1,j+1)。如下图是一个数塔,映射到该数塔上行走的规则为:从左上角的点开始,向下走或向右下走直到最底层结束。
    1
    3 8
    2 5 0
    1 4 3 8
    1 4 2 5 0
    路径最大和是1+8+5+4+4 = 22,1+8+5+3+5 = 22或者1+8+0+8+5 = 22。
    小S觉得这个问题so easy。于是他提高了点难度,他每次ban掉一个点(即规定哪个点不能经过),然后询问你不走该点的最大路径和。
    当然他上一个询问被ban掉的点过一个询问会恢复(即每次他在原图的基础上ban掉一个点,而不是永久化的修改)。

    输入

    第一行包括两个正整数,N,M,分别表示数塔的高和询问次数。
    以下N行,第i行包括用空格隔开的i - 1个数,描述一个高为N的数塔。
    而后M行,每行包括两个数X,Y,表示第X行第Y列的数塔上的点被小S ban掉,无法通行。
    (由于读入数据较大,c或c++请使用较为快速的读入方式)

    输出

    M行每行包括一个非负整数,表示在原图的基础上ban掉一个点后的最大路径和,如果被ban掉后不存在任意一条路径,则输出-1。

    样例输入

    5 3
    1
    3 8
    2 5 0
    1 4 3 8
    1 4 2 5 0
    2 2
    5 4
    1 1

    样例输出

    17
    22
    -1

    数据范围

    数据范围

    样例解释

    第一次是
    1
    3 X
    2 5 0
    1 4 3 8
    1 4 2 5 0
    1+3+5+4+4 = 17 或者 1+3+5+3+5=17
    第二次:
    1
    3 8
    2 5 0
    1 4 3 8
    1 4 2 X 0
    1+8+5+4+4 = 22
    第三次:你们都懂的!无法通行,-1!

    解法

    预处理出每个点向上走和向下走的最优值。
    那么对于ban掉(i,j),答案即为(i,k)的点的最优值(k!=j),考虑用数据结构来维护。

    代码

    const
            maxn=1007;
    type
            longint=int64;
    var
            n,m:longint;
            i,j,k:cardinal;
            a,f,g:array[0..maxn,0..maxn] of longint;
            ans:array[0..maxn,0..maxn] of longint;
            c,d:array[1..maxn] of longint;
    function max(a,b:longint):longint;
    begin
            if (a>b) then exit(a);
            exit(b);
    end;
    function lowbit(x:longint):longint;
    begin
            exit(x and (-x));
    end;
    function getmax(l,r:longint):longint;
    begin
            getmax:=0;
            while (l<=r) do
            begin
                    if (r-lowbit(r)>=l) then
                    begin
                            getmax:=max(getmax,c[r]);
                            r:=r-lowbit(r);
                    end
                    else
                    begin
                            getmax:=max(getmax,d[r]);
                            dec(r);
                    end;
            end;
    end;
    procedure change(v,v1:longint);
    begin
            d[v]:=v1;
            while (v<=n) do
            begin
                    c[v]:=max(c[v],v1);
                    v:=v+lowbit(v);
            end;
    end;
    begin
            readlN(n,m);
            for i:=1 to n do
                    for j:=1 to i do read(a[i][j]);
            for i:=1 to n do
                    for j:=1 to i do
                            g[i][j]:=max(g[i-1][j]+a[i-1][j],g[i-1][j-1]+a[i-1][j-1]);
            for i:=n downto 1 do
                    for j:=1 to i do
                            f[i][j]:=max(f[i+1][j]+a[i+1][j],f[i+1][j+1]+a[i+1][j+1]);
            for i:=1 to n do
            begin
                    fillchar(c,sizeof(c),0);
                    for j:=1 to i do
                    begin
                            change(j,f[i][j]+g[i][j]+a[i][j]);
                    end;
                    for j:=1 to i do
                    begin
                            ans[i][j]:=max(getmax(1,j-1),getmax(j+1,i));
                    end;
            end;
            ans[1][1]:=-1;
            for i:=1 to m do
            begin
                    readlN(j,k);
                    writeln(ans[j][k]);
            end;
    end.
    

    启发

    打树状数组时不要偷懒,该fillchar就要fillchar。

  • 相关阅读:
    CSS3权威指南 25.CSS3中的动画功能
    CSS3权威指南 24.CSS3中的变形处理
    CSS3权威指南 23.背景与边框相关样式
    CSS3权威指南 22.盒相关样式
    CSS3权威指南 20.使用选择器在页面中插入内容
    CSS3权威指南 19.选择器
    vivado中如何使用chipscope
    示波器X1探头和X10探头
    两个MMCM共享时钟输入时的严重警告和错误
    ZYNQ基础知识一
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714907.html
Copyright © 2020-2023  润新知