SDOI2011 消耗戰 (虛樹)

2021-10-05 06:43:20 字數 2840 閱讀 5270

題意:

給一棵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...