好久沒有學習新的知識了。
今天我學習了一下虛樹。
虛樹就是乙個不存在的樹。用來簡化問題。它只包括一些關鍵點和他的lca
我們來看看上面這一道題
給出一棵樹,含有邊權。
每次詢問給出k個點,然後詢問每個點與根斷開的最小代價。
因為資料的關係肯定沒法直接dp過去的。
首先我們可以發現可以與根到其他點的路徑沒有關係,所以只要儲存詢問點到根以及lca的資訊就可以了。那麼這就是虛樹了。
關於虛樹的構造,網上有很多部落格寫得不錯,我就不講了。
下面講怎麼虛樹上處理dp
包括兩種情況:
1.斷開自己與父親,代價為從根到該節點的最小值。
2.不考慮該點,子樹內的所有詢問點都斷開的代價。
具體看**吧。
#include
"bits/stdc++.h"
using
namespace std;
inline
intread()
#define sz(x) ((int)x.size())
#define ll long long
const
int maxn =
250000+10
;struct edge ed[maxn <<1]
;int head[maxn <<1]
, cnt;
void
add_e
(int u,
int v,
int w)
; head[u]
= cnt;
}int top[maxn]
, id[maxn]
, f[maxn]
, dep[maxn]
, sz[maxn]
, son[maxn]
, rk[maxn]
;ll mn[maxn]
;void
dfs1
(int u,
int fa,
int d)
}void
dfs2
(int u,
int t)
}int
lca(
int x,
int y)
if(dep[x]
> dep[y]
)return y;
return x;
}bool
cmp(
intconst
&a,int
const
&b)int n, m, k, a[maxn]
, s[maxn]
, st;
vector<
int> g[maxn]
;void
build
(int x)
int lca =
lca(x, s[st]);
if(lca == s[st]
)return
;while
(st >
1&& id[s[st -1]
]>= id[lca])if
(lca != s[st]
) g[lca]
.push_back
(s[st]
), s[st]
= lca;
s[++st]
= x;
}ll solve
(int u)
g[u]
.clear()
;return
min(sum, mn[u]);
}int
main()
dfs1(1
,0,1
);cnt =0;
dfs2(1
,1);
m =read()
;while
(m--
)return0;
}
P2495 SDOI2011 消耗戰 虛樹
這是我做的第一道虛樹題啊,趕腳不錯.其實虛樹也沒什麼奇怪的,就是每棵樹給你一些點,讓你多次查詢,但是我不想每次都o n 所以我們每次針對給的點建一棵虛樹,只包含這些點和lca,然後在這棵虛樹上進行樹形dp,維護每個點的最小連邊權值,這樣的複雜度就會降低不少.這裡我寫了兩種寫法 其實都是抄的 一種是正...
P2495 SDOI2011 消耗戰 虛樹
題意 一棵樹上給定點集,求到根的最小割。每次詢問只和給定的點集以及它們的lca有關係,那麼把這些點拿出來建立一棵樹。再進行樹dp。具體操作把所有詢問點按照dfn排序,再用乙個棧進行維護建樹。彈棧的時候並不是每個點都和棧中第二個元素連邊,有可能最後乙個彈棧點和新的lca連邊。dp轉移時需要查詢樹鏈的最...
SDOI2011 消耗戰 虛樹
有m次詢問,又有詢問的總的點數之和是小於等於5e5的,所以,其實就是乙個虛樹的模板了,直接用棧維護乙個虛樹即可。期間寫的時候出現了一點問題 初始化的時候,不只是要初始那些輸入的k個結點,還有k個結點的lca的衍生結點也是需要初始化的,所以初始化不到位會mle和tle的,這裡不要忘。include i...