一道:樹上差分+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 ...