並沒有參加noip2016,不過仍然聽說過這題的威名,今日一見,果然不凡操蛋
暴力分給的很足,但是暴力寫完了,離正解也不遠了
維護一下父親,每條路徑暴力跳就好了
對於鏈式,我們思考一下,怎麼跑才會產生貢獻
對於從上往下跑的,只有dis
t(st
arti
,x)=
=w
xdist(start_i,x)==w_x
dist(s
tart
i,x
)==w
x才可以被看到
稍微改改式子dep
x−de
psta
rti=
=wx—
——
—>de
psta
rti=
=dep
x−wx
dep_x-dep_==w_x————>dep_==dep_x-wx
depx−
deps
tart
i=
=wx
————
>de
psta
rti
==d
epx
−wx那麼我們建立乙個桶,遇到路徑頭就b[d
epx−
wx]+
+b[dep_x-w_x]++
b[depx
−wx
]++
,遇到路徑尾就b[d
epx−
wx]−
−b[dep_x-w_x]--
b[depx
−wx
]−−
,這樣從上往下的路徑就好了,那麼從下往上呢,稍微推一推式子,就可以發現,這是產生貢獻的東西為dep
x+wx
dep_x+w_x
depx+
wx,我們我們遇到路徑尾++++
++,再在路徑頭−−--
−−,就可以解決這個問題
這個部分頭都是路徑頭都是1,也就是根,那麼直接統計,對於每個路徑,在樹上查分,如果這個觀察員的dep
x==w
x+
1dep_x==w_x+1
depx=
=wx
+1,答案就是差分統計的值,不然就是0
這裡牽扯到了乙個和正解有關的思想
我們思考一下,仍然使用桶的思想,但是會不會出現不合法的情況呢
如果兩個點(點a,點b)在一棵子樹中,他倆的父親是起點,路徑為fa—
—>
af_a——>a
fa—
—>
a,但是如果資料巧妙,dep
x+wx
dep_x+w_x
depx+
wx也有可能滿足統計的情況,怎麼辦呢,我們從下往上統計,遇到路徑尾就往桶裡面扔,遇到頭就退掉,這樣,在return回這個點的時候,我們產生的差值就是這個點被經過的貢獻,正解也用到了這個思想。
終於到了滿分思想
首先,我們把路徑拆成兩條,乙個是u——
>lc
au——>lca
u——>lc
a,乙個是lca
——
>
vlca——>v
lca—
—>
v,對於往上的一條,我們使用乙個桶維護,詳情見40分思路,對於向下的,我們使用另外乙個桶,按照80分的思路維護,就可以得出結果
思路已經結束,但實際過程中會有很多問題
統計兩次lca導致答案變大
因為路徑拆成了兩條,所以統計兩次lca是有可能的,我們思考一下何種情況會產生
當且僅當dep
lcau
,v+w
lcau
,v==
depu
dep_}+w_}==dep_u
deplca
u,v
+wl
cau,
v=
=dep
u,這種情況下,往上的一條,該路徑條件符合,會統計一次,在往下的一條,該點仍然符合條件,會被重複統計一次,這種情況,我們只需要在讀入路徑的時候先減一即可
桶2負下標問題
這個直接平移陣列即可
乙個點是多條路徑的起點(終點)怎麼辦
我們使用鏈式前向星的方式,存起來就行
說了這麼多,**仍然不怎麼好寫,細節看**吧
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
const
int maxn =
3e5+7;
const
int n =25;
struct node
edge1[maxn*2]
,edge2[maxn*2]
,edge3[maxn*2]
;int cnt1,cnt2,cnt3,head1[maxn]
,head2[maxn]
,head3[maxn]
,ans[maxn]
;int n,m,w[maxn]
,dep[maxn]
,dis[maxn]
,len[maxn]
,be[maxn]
,en[maxn]
;int sum[maxn]
,b1[maxn*3]
,b2[maxn*3]
,f[maxn]
[n+2
],mi[n+2]
,mov=maxn;
void
add1
(int from,
int to)
void
add2
(int from,
int to)
void
add3
(int from,
int to)
void
dfs1
(int u)
}int
lca(
int a,
int b)
if(a==b)
return a;
for(
int i=
log(dep[a])/
log(2)
;i>=
0;i--)}
return f[a][0
];}void
dfs2
(int u)
b1[dep[u]]+
=sum[u]
;for
(int i=head2[u]
;i;i=edge2[i]
.next)
ans[u]
+=b1[dep[u]
+w[u]
]-t1+b2[w[u]
-dep[u]
+mov]
-t2;
for(
int i=head3[u]
;i;i=edge3[i]
.next)
}int
main()
for(
int i=
1;i<=n;i++
)scanf
("%d"
,&w[i]);
dfs1(1
);for(
int i=
1;i<=m;i++
)dfs2(1
);for(
int i=
1;i<=n;i++
)printf
("%d "
,ans[i]);
}
天天愛跑步NOIP
首先,我們考慮對於一條路徑 從x y,可以把它拆分成兩部分,圖中用虛線分開,然後這條路徑就變成了x lca,son lca y 先來考慮從x向上走到lca的路徑,對於這條路上的節點i,玩家能對節點i產生貢獻的前提是deep x w i deep i 移項可得deep x w i deep i 也就是...
NOIP2016 天天愛跑步
時間限制 2 s 記憶體限制 512 mb 題目描述 小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一棵包含n個結點和n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。...
NOIP2016天天愛跑步
小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn n個結點和 n 1n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11 1到nn...