◇題目傳送門◆
考慮如果直接模擬每個人的路徑複雜度就會達到o(n
m)
o(nm)
o(nm
)級別,這樣做肯定要**。
於是換個方向思考:我們以觀察員的視角來解決這道題。即我們統計每個人對於每個觀察員的貢獻。
對於第i
ii個人的行動,我們可以分成兩部分來看:
記u
uu是s,t
s,ts,
t的最近公共祖先,d(u
)d(u)
d(u)
為節點u
uu的深度。
當當前人是從s
ss走到u
uu的時候:
則我們通過畫圖可以知道:
對於該路徑上任何乙個節點v
vv,當d(s
)=wv
+d(v
)d(s)=w_v+d(v)
d(s)=w
v+d
(v)時,這個人會對v
vv點上的觀察員做出貢獻。即人從s
ss出發,在w
vw_v
wv秒時被v
vv節點上的觀察員看到。
當人從u
uu走向t
tt的時候:通過畫圖可以知道:
對於該路徑上的任何乙個節點v
vv,若有d(s
)−2d
(u)=
wv−d
vd(s)-2d(u)=w_v-d_v
d(s)−2
d(u)
=wv
−dv
,則這個人會對節點v
vv上的觀察員做出貢獻。
相當於在s
ss處出現了數d(s
)d(s)
d(s)
,在u
uu的父親節點處消失;在u
uu處出現了數d(s
)−2d
(u
)d(s)-2d(u)
d(s)−2
d(u)
,在t
tt處消失。
則問題轉化為在以u
uu為根的子樹中,統計有多少個第一類數等於wu+
d(u)
w_u+d(u)
wu+d(
u)和第二類數等於wv−
d(v)
w_v-d(v)
wv−d(
v)。於是做樹上差分:開兩個統計兩類數的出現和消失的位置的vector
和計數陣列,一遍dfs
dfsdf
s即可,總時間複雜度為o(m
logn+
n)
o(m\log n+n)
o(mlogn+
n)。似乎我寫的常數有點大。。。
#include
#include
#include
using
namespace std;
const
int maxn =
3e5;
const
int maxlog =19;
int n, m;
int w[maxn +5]
;vector<
int> g[maxn +5]
;void
addedge
(int u,
int v)
int dep[maxn +5]
;int fa[maxn +3]
[maxlog +2]
;void
predfs
(int u,
int pre)
}inline
intlca
(int u,
int v)
int sum1[maxn +5]
, sum2[maxn *2+
5];int ans[maxn +5]
;vector<
int> a1[maxn +5]
, a2[maxn +5]
, b1[maxn +5]
, b2[maxn +5]
;void
dfs(
int u,
int pre)
for(
int i =
0; i <
(int
)a1[u]
.size()
; i++
) sum1[a1[u]
[i]]++;
for(
int i =
0; i <
(int
)a2[u]
.size()
; i++
) sum1[a2[u]
[i]]--;
for(
int i =
0; i <
(int
)b1[u]
.size()
; i++
) sum2[b1[u]
[i]+ n]++;
for(
int i =
0; i <
(int
)b2[u]
.size()
; i++
) sum2[b2[u]
[i]+ n]--;
ans[u]
+= sum1[dep[u]
+ w[u]
]+ sum2[w[u]
- dep[u]
+ n]
;//將這棵子樹差分後的正確答案加回去
}int
main()
predfs(1
,0);
for(
int i =
1; i <= n; i++
)scanf
("%d"
,&w[i]);
for(
int i =
1; i <= m; i++
)dfs(1
,0);
for(
int i =
1; i < n; i++
)printf
("%d "
, ans[i]);
printf
("%d\n"
, ans[n]);
return0;
}
洛谷P1600 天天愛跑步 差分 LCA 桶
題目鏈結 一步一步的來考慮 25 直接 o nm 的暴力 鏈的情況 維護兩個差分陣列,分別表示從左向右和從右向左的貢獻,s i 1 統計每個點的子樹內有多少起點即可 t i 1 同樣還是差分的思想,由於每個點 能對其產生的點的深度是相同的 假設為 x 那麼訪問該點時記錄下 dep x 的數量,將結束...
洛谷 P1600 天天愛跑步
題面就不貼上了 把每個玩家的路徑拆成一條到lca的路徑和從lca到終點的路徑 然後,使用樹上差分統計答案即可 那麼,樹上差分是什麼?差分的具體思想是,當某區間內某元素對答案有貢獻,就在區間起點打乙個 1 標記代表多出了乙個對答案有貢獻的元素,在終點打乙個 1標記代表乙個對答案有貢獻的元素在該位置 結...
洛谷P1600 天天愛跑步
樹上的題有點意思啊 這題我最開始的想法是 固定乙個觀測點i,能觀測到的一定是起點距離 i 為 w i 的點的子集合。問題是這個集合只有一部分的點會經過 i 點,就很煩。於是得換個思路,不放固定乙個跑步的人 x 觀察他對哪些觀察者 i 產生了貢獻。於是我們得到了公式,對於上公升階段的點來說,不妨設 s...