天天愛跑步

2021-09-29 08:08:38 字數 3288 閱讀 3133

一道:樹上差分+lca+桶的題

說實話,這道題放在d1t2就是非常不合理的。然而ccf就是放了,並且還是能依靠csp撈錢,你也必須交錢參加比賽。這個社會是多麼的不公啊!閒扯結束

顯然如果對每條路徑都進行一次處理,複雜度不對。考慮對路徑進行一次預處理,然後進行統一的計算答案。我們發現當一條路徑對某乙個點p產生貢獻時滿足這個條件:

1.當p

pp在該路徑的s

ss與lca

lcalc

a之間時 dep

[s]−

dep[

p]=w

atch

[p

]dep[s]-dep[p]=watch[p]

dep[s]

−dep

[p]=

watc

h[p]

移一下項為dep

[s]=

dep[

p]+w

atch

[p

]dep[s]=dep[p]+watch[p]

dep[s]

=dep

[p]+

watc

h[p]

那麼該路徑起點對p有貢獻

2.當p

pp在該路徑的lca

lcalc

a與tt

t之間時 dis

t[s,

t]−w

atch

[p]=

dep[

t]−d

ep[p

]dist[s,t]-watch[p]=dep[t]-dep[p]

dist[s

,t]−

watc

h[p]

=dep

[t]−

dep[

p]移一下項dis

t[s,

t]−d

ep[t

]=wa

tch[

p]−d

ep[p

]dist[s,t]-dep[t]=watch[p]-dep[p]

dist[s

,t]−

dep[

t]=w

atch

[p]−

dep[

p]那麼該路徑終點對p有貢獻

然後用乙個全域性桶維護這些貢獻 當列舉到當前點的時候 將當前點作為終點和起點的貢獻加在桶裡面。然後計算當前點的ans

細節:乙個它只會受其子樹的貢獻,其他的貢獻不會有的。如何處理?在開始遍歷這個點的時候用ad1

,ad2

ad1,ad2

ad1,ad

2來儲存已經存在的桶裡面的值 然後遍歷子樹 當又返回到當前節點的時候 計算當前節點的答案。顯然當前節點的答案為ans

[x]+

=bas

1[wa

tch[

x]+d

ep[x

]]−a

d1+b

as2[

watc

h[x]

−dep

[x]+

maxn

]−ad

2ans[x]+=bas1[watch[x]+dep[x]]-ad1+bas2[watch[x]-dep[x]+maxn]-ad2

ans[x]

+=ba

s1[w

atch

[x]+

dep[

x]]−

ad1+

bas2

[wat

ch[x

]−de

p[x]

+max

n]−a

d2注意到我們對bas

2bas2

bas2

的計算的時候加了乙個max

nmaxn

maxn

,其實原因很顯然 wat

ch[x

]−de

p[x]

watch[x]-dep[x]

watch[

x]−d

ep[x

]有可能小於零

還有就是當遍歷完當前點 應該將以當前點為lca的路徑的影響全部消除。因為如果以當前點為lca,顯然不會對當前點的父親及祖先產生影響,應該減掉

然後就是**了qaq 我是用的鄰接表儲存的以當前節點為終點的路徑編號,以及以當前節點為lca的路徑編號

#include #include #include #include #define int long long 

using namespace std;

const int maxn=500010;

int read()

while(ch>='0' && ch<='9')

return x*f;

}int n,m,fir[maxn],nxt[maxn<<1],to[maxn<<1],tot=1,watch[maxn],fa[maxn][25];

int st[maxn],ed[maxn],stt[maxn],dist[maxn],ans[maxn],dep[maxn];

int fir1[maxn],nxt1[maxn<<1],to1[maxn<<1],tot1,fir2[maxn],nxt2[maxn<<1],to2[maxn<<1],tot2;

void add(int x,int y)

void dfs1(int x)

}int lca(int x,int y)

for(int i=20;i>=0;i--)

} return fa[x][0];

}void add1(int x,int y)

void add2(int x,int y)

int bas1[maxn<<1],bas2[maxn<<1],ad1,ad2;

void dfs2(int x)

bas1[dep[x]]+=stt[x];

for(int i=fir1[x];i;i=nxt1[i])

ans[x]+=bas1[watch[x]+dep[x]]-ad1+bas2[watch[x]-dep[x]+maxn]-ad2;

for(int i=fir2[x];i;i=nxt2[i])

}signed main()

for(int i=1;i<=n;i++) watch[i]=read();

dep[1]=1;

dfs1(1);

for(int i=1,x,y,lca;i<=m;i++)

dfs2(1);

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

printf("%lld ",ans[i]);

}

跑步愛天天

對於 50 的資料 直接模擬 對於另外10 的資料 因為地圖是一條鏈,顯然 yousiki 會消滅所有距離他為偶數條邊的祖 先。對於100 的資料 我們先把整個樹 dfs 一遍,遇到乙個點就把這個點記錄到乙個陣列後邊,即求出了樹的尤拉序,顯然如果不考慮迴圈的話,guard是在這個序列上每次往後走乙個...

天天愛跑步

終於拿下noip最難一題 看別人的題解看不懂 於是準備寫一篇更通俗易懂雜亂無章的題解 樹上差分 線段樹 桶 lca 將每條路徑在lca處切成上公升路徑和下降路徑 會發現對於x號觀察員若觀察到玩家i 則必有dep i w x depx 或dep i 2 dep lca w x depx 我們用桶標記 ...

天天愛跑步

暴力程式 25pts 複雜度 o n 2 includeusing namespace std const int maxn 3e5 10 int n,m,ans maxn inline int read while c 0 c 9 return x f int beg maxn nex maxn ...