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.
原文地址:https://www.cnblogs.com/oldjang/p/6168364.html