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

2021-09-10 09:38:37 字數 3244 閱讀 1190

有一棵n

nn個點的樹。

有m

mm個人,第i

ii個人從x

ix_i

xi​開始,以每秒1條邊的速度向y

iy_i

yi​跑。

每個點有乙個觀察員在第t

it_i

ti​秒觀察,求每個點的觀察員能觀察到幾個人。

首先把一條路拆成向上和向下的兩條,分別考慮。

向上的路徑,如果能對x

xx產生貢獻,必須滿足:

1.stst

st在x

xx的子樹裡

2.e ded

ed在x

xx的外部(實際上就是在x

xx到根的鏈上)

3.d pt

[st]

=dpt

[x]+

t[x]

dpt[st]=dpt[x]+t[x]

dpt[st

]=dp

t[x]

+t[x

](dp

tdpt

dpt表示深度,stst

st表示路徑的起點,eded

ed表示終點)

向下的路徑,如果能對x

xx產生貢獻,必須滿足:

1.eded

ed在x

xx的子樹裡

2.s tst

st在x

xx的外部(實際上就是在x

xx到根的鏈上)

3.d pt

[st]

−t1[

st]=

dpt[

x]−t

[x

]dpt[st]-t1[st]=dpt[x]-t[x]

dpt[st

]−t1

[st]

=dpt

[x]−

t[x]

(t 1t1

t1表示出發時間,因為可能接在向上的路徑之後)

發現條件有點多,比較難處理。首先我想的是線段樹合併(並沒有a掉,而且現在還不知道錯在**)。

每個點一棵權值線段樹,存向上路徑的dpt

[st]

dpt[st]

dpt[st

]數量和向下路徑的dpt

[st]

−t1[

st

]dpt[st]-t1[st]

dpt[st

]−t1

[st]

數量,在較深的點+1,在較淺的點的上方-1。動態開點,時間空間複雜度其實都沒有問題,但是又re又wa不知道為什麼。

然後此時看到了題解中的差分+桶。

其實桶比線段樹多存的就是較深的點的dfn在當前點之前,較淺的點卻還沒有被退棧的路徑,換句話說就是在當前子樹之外,卻還在桶內的點。最開始因為不知道如何處理這個所以沒有繼續想下去。

然後此時又在茫茫題解中看到了chy神仙的題解。

只要在當前節點剛剛入棧的時候記錄一下當前桶裡的值,後來再減掉就好了。

太精闢了喂。可能這就是神仙吧。非常簡單但是很厲害。

#include

#define pb push_back

using

namespace std;

const

int n =

3e5+10;

const

int m = n<<1;

const

int e =20;

int n, m, tim[n]

;struct g

void

add(

int u,

int v)

}g;int dpt[n]

, f[n]

[e];

vector<

int> st1[n]

, ed1[n]

, st2[n]

, ed2[n]

;int ton1[n<<1]

, ton2[n<<1]

, ans[n]

;void

dfs(

int u,

int fa)

}int

lca(

int x,

int y)

intson

(int x,

int y)

void

dfs1

(int u,

int fa)

ans[u]

= ton1[dpt[u]

+tim[u]

]+ton2[dpt[u]

-tim[u]

+n]-tmp;

for(

int i =

0, ub = ed1[u]

.size()

; i < ub;

++ i)

-- ton1[ed1[u]

[i]]

;for

(int i =

0, ub = ed2[u]

.size()

; i < ub;

++ i)

-- ton2[ed2[u]

[i]];}

intmain()

dpt[0]

=-1;

dfs(1,

0);for

(int i =

1; i <= n;

++ i)

scanf

("%d"

,&tim[i]);

for(

int i =

1; i <= m;

++ i)

}memset

(ans,0,

sizeof

(ans));

memset

(ton1,0,

sizeof

(ton1));

memset

(ton2,0,

sizeof

(ton2));

dfs1(1

,0);

for(

int i =

1; i <= n;

++ i)

printf

("%d "

, ans[i]);

return0;

}

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 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...