NOIP2016 天天愛跑步(樹上差分)

2022-05-19 21:31:29 字數 1902 閱讀 2978

給定一棵樹,從時刻 0 開始,有若干人從 s[i] 出發向 t[i] 移動,每單位時刻移動一條邊

對於樹上每個點 x,求 w[x]  時刻有多少人恰好路過 x

n,m≤300000

從上午11點做到下午3點45終於做出來了。

一開始堅持自己的想法,發現錯了之後不知道怎麼改,無奈看了題解。

列出恰好路過的條件並化簡

在 si 到 lca(si,ti ) 階段,應滿足 d[si ]=w[x]+d[x]

在 lca(si,ti ) 到 ti階段,應滿足 d[si]-2∗d[lca(si,ti )]=w[x]-d[x]

相當於在 si 位置出現乙個 a 類數 d[si ],在 lca(si,ti ) 的父節點消失

在 ti 位置出現乙個 b 類數 d[si ]-2∗d[lca(si,ti )],在 lca(si,ti ) 消失

求子樹 x 中,等於 w[x]+d[x] 的 a 類數個數 + 等於 w[x]-d[x] 的 b 類數個數

全域性陣列計數,統計遍歷子樹 x 前後相應位置上的差我一開始就是沒注意這死活調不出來

1 #include2 #include3 #include4 #include5 #include6 #include7

using

namespace

std;

8const

int n=300010

;9 vectorv1[n],v2[n],v3[n],v4[n];

10int

cnt,head[n];

11int fa[n][32

],dep[n];

12int book1[n],book2[n*2

];13

intn,m,w[n],ans[n];

14struct

edgee[n*2

];17

void add(int u,int

v)23

void dfs1(int u,int f,int

deep)31}

32int lca(int u,int

v)37

if(u==v)return

u;38

for(int i=30;i>=0;i--)42}

43return fa[u][0

];44}45

void dfs2(int

u)50

for(int i=0;i)

53for(int i=0;i)

56for(int i=0;i)

59for(int i=head[u];i;i=e[i].nxt)

64 ans[u]=book1[w[u]+dep[u]]+book2[w[u]-dep[u]+n]-ans[u];65}

66int

main()

74 dfs1(1,0,1

);75

for(int i=1;i<=30;i++)

76for(int j=1;j<=n;j++)

77 fa[j][i]=fa[fa[j][i-1]][i-1

];78

for(int i=1;i<=n;i++)

81for(int i=1;i<=m;i++)

90for(int i=0;i0].size();i++)

93for(int i=0;i0].size();i++)

96for(int i=0;i0].size();i++)

99for(int i=0;i0].size();i++)

102 dfs2(1

);103

for(int i=1;i<=n;i++)

106return0;

107 }

view code

NOIP2016 天天愛跑步

時間限制 2 s 記憶體限制 512 mb 題目描述 小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一棵包含n個結點和n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。...

NOIP2016天天愛跑步

小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn n個結點和 n 1n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11 1到nn...

NOIP2016 天天愛跑步

看這道題不爽很久了,但一直沒有開它,原因是我不會 我太菜了 看了題解還是寫不來,因為我不會線段樹合併。然後今天學了dsu on tree這種神奇的科技,成功把它a了,效率吊打線段樹合併。於是寫篇題解紀念一下。洛谷p1600 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...