題意:
給一棵n個頂點的樹,每條樹邊有邊權。
m次詢問,每次詢問給出k個點,問使得這k個點均不與1號點(根節點)相連的最小代價
解法:
虛樹用法:
在單次詢問只涉及樹中少量節點時,可以建立一顆只包含關鍵節點的樹
將無用節點組成的鏈簡化為邊或者刪掉,形成虛樹,最後在虛樹上進行dp
關鍵點為詢問點和lca
虛數上dp的複雜度:
顯然虛數的葉子節點一定是詢問點,
當詢問中的k個點都是葉子的時虛樹形態最大,有2k-
1個點,樹形dp複雜度為o
(2k)
虛樹形態最大的時是乙個二叉樹
建樹前預處理:
dfs序,lca,將詢問點按dfs序排序
建樹大致流程:
用棧維護最右鏈
先無條件將第乙個詢問點入棧
接下來一次處理詢問點,假設當前點為now,now和top的lca為lc
有4種情況:
1.lc=top,那麼now在top的子樹中,那麼now直接入棧
2.lc在top和top-
1之間,那麼將top加入虛樹,lc和now入棧
3.lc=top-
1,此時和2差不多,top加入虛樹,lc不入棧,now入棧
4.d[lc]
,即lc在top-
1上面,此時不斷出棧加入虛樹直到變為情況2
當所有詢問點都處理完之後將最右鏈加入虛樹即可
建完樹之後:
標記詢問點,對虛樹樹形dp,只針對詢問點dp就行了
回溯的時候順便清空邊陣列和詢問點的標記
注意事項:
1.當棧中只有乙個元素的時候,訪問top-
1會越界,因此要用陣列模擬棧,
且棧從1開始,這樣top-
1就是0了,令d[0]
=0就可以了
這樣的話會存在0到stk[top]的邊,如果建樹用的是單向邊,不從點0開始dfs就沒有影響,雙向邊的話判斷一下點0就行了
2.清空虛樹要在dfs訪問完乙個節點的時候清空才能保證複雜度
不能在最後清空詢問點,因為虛樹中不止存在詢問點,還存在一些lca
3.虛樹的根是最後棧中的第乙個節點(如果是有向樹的話)
,或者說最後棧中的第乙個節點一定在虛樹中.
code:#include
using
namespace std;
#define ll long long
const
int maxm=
5e5+5;
int head[maxm]
,nt[maxm]
,to[maxm]
,w[maxm]
,cnt;
int head2[maxm]
,nt2[maxm]
,to2[maxm]
,cnt2;
int n;
void
add(
int x,
int y,
int z)
void
add2
(int x,
int y)
//const
int maxd=20;
int dep[maxm]
,id[maxm]
,idx;
int stk[maxm]
,top;
int f[maxm][25
];bool mark[maxm]
;ll mi[maxm]
;ll dp[maxm]
;void
dfs1
(int x,
int fa)
}void
lca_init()
}}intlca
(int a,
int b)
if(a==b)
return a;
for(
int i=maxd;i>=
0;i--)}
return f[a][0
];}bool
cmp(
int a,
int b)
void
dfs(
int x)
if(mark[x]
)dp[x]
=mi[x]
;//如果是標記點
else dp[x]
=min
(temp,mi[x]);
head2[x]=0
;//順便清空
mark[x]=0
;}int c[maxm]
;void
solve()
sort
(c+1
,c+1
+k,cmp)
; top=0;
stk[
++top]
=c[1];
for(
int i=
2;i<=k;i++
)else
}break;}
else
} stk[
++top]
=now;
//最後now都要入棧
}while
(top>=2)
dfs(stk[1]
);//stk[1]是虛樹的根
cout<]<}signed
main()
mi[1]
=1e18
;dfs1(1
,-1)
;lca_init()
;int q;cin>>q;
while
(q--
)return0;
}
SDOI2011 消耗戰 虛樹
有m次詢問,又有詢問的總的點數之和是小於等於5e5的,所以,其實就是乙個虛樹的模板了,直接用棧維護乙個虛樹即可。期間寫的時候出現了一點問題 初始化的時候,不只是要初始那些輸入的k個結點,還有k個結點的lca的衍生結點也是需要初始化的,所以初始化不到位會mle和tle的,這裡不要忘。include i...
虛樹 sdoi2011《消耗戰》
卡著時間過得,大概是因為全用了ll,時間漲了一倍吧?懶得改了,第一道虛樹還是思路比較重要 下面這段文字是複製來的 給出一棵樹.每次詢問選擇一些點,求一些東西.這些東西的特點是,許多未選擇的點可以通過某種方式剔除而不影響最終結果.於是就有了建虛樹這個技巧.我們可以用log級別的時間求出點對間的lca....
SDOI2011 消耗戰 虛樹 樹形動規)
虛樹的主要思想 所以怎麼辦 q.clear int m scanf d m for int i 1 i m i sort q.begin q.end cmp for int i 0 iq是乙個vector,我們開始先對所有節點按尤拉序 即深度優先搜尋是訪問的順序 排序,然後對每兩個相鄰的節點將lca...