• bzoj3631 [JLOI2014]松鼠的新家


    3631: [JLOI2014]松鼠的新家

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1727  Solved: 834
    [Submit][Status][Discuss]

    Description

    松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。
    可是这样会导致**重复走很多房间,懒惰的**不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。**是个馋家伙,立马就答应了。
    现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。

    Input

    第一行一个整数n,表示房间个数
    第二行n个整数,依次描述a1-an
    接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

    Output

    一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让**有糖果吃。

    Sample Input

    5
    1 4 5 3 2
    1 2
    2 4
    2 3
    4 5

    Sample Output

    1
    2
    1
    2
    1

    HINT

    2<= n <=300000

    题解

    题目大意:给定一棵树,在树上对若干条树链整体加1,问最后每个点的权值是多少。

    很裸的树上差分。对于每条树链(u,v),开一个前缀和数组sum,在u处+1,v处+1,lca(u,v)处-1,father(lca(u,v))处-1即可,统计最终答案时ans[i]=sigma(ans[j])+sum[i]{j为i的儿子}。

    还有一点要注意,根据题目意思,前一次的路径的结尾就是下一次路径的开头,相邻两次走的路径会有一个点重复计算,所以统计完ans数组之后要记得把该减的减一

    当然,这题也可以树剖……

    /**************************************************************
        Problem: 3631
        User: 1090900715
        Language: Pascal
        Result: Accepted
        Time:2440 ms
        Memory:36024 kb
    ****************************************************************/
     
    program j01;
    const maxn=300086;
    var sum:array[0..maxn]of longint;
        a,ans:array[0..maxn]of longint;
        dep:array[0..maxn]of longint;
        fa:array[0..maxn,0..19]of longint;
        head:array[0..maxn]of longint;
        q,next:array[0..2*maxn]of longint;
        tot,n,tt,u,v,i,lc:longint;
     
    procedure swap(var a,b:longint);
    var c:longint;
    begin
      c:=a;a:=b;b:=c;
    end;
     
    procedure add(u,v:longint);
    begin
      inc(tt);
      q[tt]:=v;
      next[tt]:=head[u];
      head[u]:=tt;
    end;
     
    procedure dfs(i:longint);
    var j:longint;
    begin
      for j:=1 to 19 do
      begin
        if (1 shl j)>dep[i] then break;
        fa[i,j]:=fa[fa[i,j-1],j-1];
      end;
      j:=head[i];
      while j>0 do
      begin
        if q[j]<>fa[i,0] then
        begin
          fa[q[j],0]:=i;
          dep[q[j]]:=dep[i]+1; 
          dfs(q[j]);
        end;
        j:=next[j];
      end;
    end;
     
    function lca(u,v:longint):longint;
    var i,d:longint;
    begin
      if dep[u]<dep[v] then swap(u,v);
      d:=dep[u]-dep[v];
      for i:=0 to 19 do
        if d and(1 shl i)>0 then u:=fa[u,i];
      for i:=19 downto 0 do
        if fa[u,i]<>fa[v,i] then
        begin
          u:=fa[u,i];v:=fa[v,i];
        end;
      if u=v then exit(u) else exit(fa[u,0]);
    end;
     
    procedure dfs2(i:longint);
    var j:longint;
    begin
      ans[i]:=sum[i];
      j:=head[i];
      while j>0 do
      begin
        if q[j]<>fa[i,0] then
        begin
          dfs2(q[j]);
          ans[i]:=ans[q[j]]+ans[i];
        end;
        j:=next[j];
      end;
    end;
     
    begin
      readln(n);
      for i:=1 to n do read(a[i]);
      fillchar(head,sizeof(head),0);tt:=0;
      for i:=1 to n-1 do
      begin
        readln(u,v);
        add(u,v);
        add(v,u);
      end;
      fa[1,0]:=0;dep[1]:=0;
      dfs(1);
      for i:=2 to n do
      begin
        u:=a[i];v:=a[i-1];
        lc:=lca(u,v);
        inc(sum[u]);inc(sum[v]);
        dec(sum[lc]);dec(sum[fa[lc,0]]);
      end;
      dfs2(1);
      for i:=2 to n do dec(ans[a[i]]);
      for i:=1 to n do writeln(ans[i]);
    end.
  • 相关阅读:
    vs中无法找到头文件
    c++ vector 用法
    c++ queue 用法
    c++ 中 毫秒级时间获取
    vs2013 boost signals
    vs2013环境下boost配置
    C++ static 用法
    fopen()和fclose()
    删除字符串尾的回车符
    WaitForSingleObject()
  • 原文地址:https://www.cnblogs.com/oldjang/p/6168364.html
Copyright © 2020-2023  润新知