題目鏈結
題意
有乙個樹狀的城市網路(即 n 個城市由 n-1 條道路連線的連通圖),首都為 1 號城市,每個城市售賣價值為 a_i 的珠寶。
現在安排有 q 次行程,每次行程為從 u 號城市前往 v 號城市(走最短路徑),保證 v 在 u 前往首都的最短路徑上。 在每次行程開始時,你手上有價值為 c 的珠寶,每經過乙個城市時(包括 u 和 v ),假如那個城市中售賣的珠寶比你現在手上的所有珠寶的最大值要優秀(價值更高,即嚴格大於),那麼你就會選擇購入。現在你想要對每一次行程,求出會進行多少次購買事件。
思路
保證v在u通往首都的最短路上,也就是說v是u,v的lca,從u到v,每經過乙個珠寶價值比手上的珠寶價值大的城市,就要購買一次,並非是最長上公升子串行,而是只要是比手上的珠寶價值大就要買,且買了後,手上的最大的珠寶價值變成了剛買的珠寶價值了。考慮倍增的思想,f[i][j]表示從i往上走,能買珠寶的第2^j個點是哪個,預處理處倍增陣列,顯然,只要求出f[i][0],其他的就可以用f[i][j] = f[fi[j - 1][j - 1]求得(就像lca求倍增陣列的方法)。那麼如何解f[i][0],如果i的父親節點x,滿足val[i]=val[x],那麼就要從父親節點開始,去找第乙個比val[i]大的節點,這裡可以用倍增去求得,考慮f[x][k],k從大到小列舉,這樣可以快速縮短距離,如果val[f[x][k]]<=val[i],則x=f[x][k],從f[x][k]節點開始往上找;否則就找f[x][k-1],判斷val[f[x][k - 1]]是否大於val[i],如此不斷的趨近i上面的第乙個比它大的值,最後找到的那個f[x][0]就是f[i][0]。
求解完倍增陣列後,接下來就是處理詢問了,題目問的是從u開始就有了價值為c的珠寶,那麼我們新建乙個節點與u點相連,價值為c,這樣就可以直接求到這個點的倍增陣列,通過該點的倍增陣列來求解。從u到v的購買次數,也就是通過倍增陣列從u往上跳,跳的總距離(從該點到父親距離為1,如f[i][0]距離為1,f[i][1]距離為2)。因為v點不一定在u點的祖先節點上,題目保證v一定在u到根節點的路徑上,所以v得深度一定比u小,所以用dep來判斷是否應該停止向上跳。
#include
using
namespace std;
const
int maxn =
2e5+7;
typedef
long
long ll;
int n, q, a[maxn]
;int head[maxn]
, to[maxn<<1]
, nex[maxn<<1]
, tot;
void
add(
int x,
int y)
int to[maxn]
, f[maxn][20
], dep[maxn]
;//fa[u][i]:儲存u結點往根方向第2^i個val大於它的結點
void
dfs(
int x,
int fx)
f[x][0
]= f[p][0
];//得到第乙個比val[u]的的祖先結點
}for
(int i =
1; i <=
19; i++
)//倍增陣列,遞推
f[x]
[i]= f[f[x]
[i -1]
][i -1]
;for
(int i = head[x]
;~i; i = nex[i])}
intmain()
for(
int i =
1, x, y, z; i <= q; i++
)dfs(1
,0);
for(
int i =
1; i <= q; i++)}
printf
("%d\n"
, ans);}
return0;
}
樹上倍增 城市網路
題解 題目中保證了u到v一定在最短路徑上,所以考慮用樹上倍增的方法。我們fa陣列存的是比當前節點val值嚴格大的最近祖先。然後每次倍增的時候更新答案就可以了。include using namespace std typedef long long ll const int n 2e5 7 int ...
牛客 城市網路 樹上倍增
題意 給一棵 n nn 個點的樹,每個節點代表乙個城市,每個城市賣價值為 a ia i ai 的珠寶,有 q qq 次詢問,每次詢問從 u uu 城市到 v vv 城市,一開始有價值為 c cc 的珠寶,如果當前經過的城市珠寶價值大於已有的所有珠寶的最大價值,就購買。保證 v vv 在 u uu 到...
LOJ 6192 城市網路(樹上倍增)
一棵以 1 號節點為根的樹,每個點有乙個權值,有 q 個詢問,每次從 x 點開始往某個祖先 y 走,初始有權值 c 如果路徑上遇到更大的權值,那麼 c 改為那個權值,問會修改多少次。資料範圍 n leq 2 times 10 5 首先因為本題沒有修改操作,所以可以離線維護。然後我們發現如果我們在 x...