P2495 SDOI2011 消耗戰 虛樹

2022-03-13 05:22:22 字數 4663 閱讀 1720

這是我做的第一道虛樹題啊,趕腳不錯.其實虛樹也沒什麼奇怪的,就是每棵樹給你一些點,讓你多次查詢,但是我不想每次都o(n),所以我們每次針對給的點建一棵虛樹,只包含這些點和lca,然後在這棵虛樹上進行樹形dp,維護每個點的最小連邊權值,這樣的複雜度就會降低不少.這裡我寫了兩種寫法(其實都是抄的),一種是正常建樹的正常做法,還有一種是不用建樹,只用堆維護,模擬一棵樹的操作,維護尤拉序,就是乙個點有進入的編號,也有出去的編號.這樣就可以不用真正建出虛樹而能進行查詢.

題幹:

題目描述

在一場戰爭中,戰場由n個島嶼和n-1個橋梁組成,保證每兩個島嶼間有且僅有一條路徑可達。現在,我軍已經偵查到敵軍的總部在編號為1的島嶼,而且他們已經沒有足夠多的能源維繫戰鬥,我軍勝利在望。已知在其他k個島嶼上有豐富能源,為了防止敵軍獲取能源,我軍的任務是炸毀一些橋梁,使得敵軍不能到達任何能源豐富的島嶼。由於不同橋梁的材質和結構不同,所以炸毀不同的橋梁有不同的代價,我軍希望在滿足目標的同時使得總代價最小。

偵查部門還發現,敵軍有一台神秘機器。即使我軍切斷所有能源之後,他們也可以用那台機器。機器產生的效果不僅僅會修復所有我軍炸毀的橋梁,而且會重新隨機資源分布(但可以保證的是,資源不會分布到1號島嶼上)。不過偵查部門還發現了這台機器只能夠使用m次,所以我們只需要把每次任務完成即可。

輸入輸出格式

輸入格式:

第一行乙個整數n,代表島嶼數量。

接下來n-1行,每行三個整數u,v,w,代表u號島嶼和v號島嶼由一條代價為c的橋梁直接相連,保證1<=u,v<=n且1<=c<=100000

。第n+1行,乙個整數m,代表敵方機器能使用的次數。

接下來m行,每行乙個整數ki,代表第i次後,有ki個島嶼資源豐富,接下來k個整數h1,h2,…hk,表示資源豐富島嶼的編號。

輸出格式:

輸出有m行,分別代表每次任務的最小代價。

輸入輸出樣例

輸入樣例#

1: 複製101

51319

62119

2482

39156

8754

78311079

32106

4578

3394

6輸出樣例#

1: 複製

1232

22

不用建樹版本的**:

//

luogu-judger-enable-o2

#include#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define duke(i,a,n) for(register int i = a;i <= n;i++)

#define lv(i,a,n) for(register int i = a;i >= n;i--)

#define clean(a) memset(a,0,sizeof(a))

const

long

long inf = 1ll << 50

;typedef

long

long

ll;typedef

double

db;template

void read(t &x)

template

void

write(t x)

const

int n = 250010

;struct

node

a[2 *n];

int lst[n],len = 0

,n,m;

void add(int x,int

y,ll w)

int dfin[n],cnt = 0,tr[4 * n],fa[n][22

];int

dep[n],dfout[n];

ll mi[n],sum[n];

bool

book[n];

stack

s;bool cmp(int x,int

y)void dfs(int

x)

for(int k = lst[x];k;k =a[k].nxt)

}dfout[x] = ++cnt;

return;}

int lca(int u,int

v) }

if(u == v) return

u;

for(int i = 20;i >= 0;i--)

}return fa[v][0];}

void

cl_st()

intmain()

mi[1] =inf;

dfs(1);

read(m);

duke(i,

1,m)

//cout<<"a",cmp);

duke(j,

1,cot - 1

)

}//cout<<"b"for(int j = 1;j <= nc;j++)

if(!book[1

])

sort(tr + 1,tr + cot + 1

,cmp);

//cout<<"c",cot)

else

else

sum[now] = 0

; book[now] = false

; }}}

return0;

}

建樹的**:

#include#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define duke(i,a,n) for(int i = a;i <= n;i++)

#define lv(i,a,n) for(int i = a;i >= n;i--)

#define clean(a) memset(a,0,sizeof(a))

#define mp make_pair

#define cp complex#define enter puts("")

const

long

long inf = 1ll << 60

;const

double eps = 1e-8

;typedef

long

long

ll;typedef

double

db;template

void read(t &x)

template

void

write(t x)

const

int n = 250010

;int n,dfn[n],tot = 0

,cnt,m,_top;

ll mn[n];

ints[n];

namespace

t a[

2 *n];

int lst[n],dep[n],f[n],tp[n],son[n],siz[n],len = 0

; inline

void add(int x,int y,int

w)

void dfs1(int u,int fa,int

depth)}}

void dfs2(int u,int

t)

}inline

int lca(int x,int

y)

if(dep[x] >dep[y]) swap(x,y);

return

x; }

}namespace

ft inline

bool cmp(int a,int

b)

inline

void ins(int

x)

int lca =t :: lca(x,s[_top]);

//cout;

while(_top > 1 && dfn[s[_top - 1]] >= dfn[lca]) add(s[_top - 1],s[_top]),_top --;

if(lca != s[_top]) add(lca,s[_top]),s[_top] =lca;

s[++_top] =x;

}ll pr(

intx)

v[x].clear();

return

min(ans,mn[x]);

}}int

a[n];

intmain()

t :: dfs1(

1,0,1

); t :: dfs2(

1,1);

/*duke(i,1,n)

printf("%d ",dfn[i]);

puts("");

*/int

x,y;

read(m);

while(m--)

return0;

}

虛樹 P2495 SDOI2011 消耗戰

好久沒有學習新的知識了。今天我學習了一下虛樹。虛樹就是乙個不存在的樹。用來簡化問題。它只包括一些關鍵點和他的lca 我們來看看上面這一道題 給出一棵樹,含有邊權。每次詢問給出k個點,然後詢問每個點與根斷開的最小代價。因為資料的關係肯定沒法直接dp過去的。首先我們可以發現可以與根到其他點的路徑沒有關係...

P2495 SDOI2011 消耗戰 虛樹

題意 一棵樹上給定點集,求到根的最小割。每次詢問只和給定的點集以及它們的lca有關係,那麼把這些點拿出來建立一棵樹。再進行樹dp。具體操作把所有詢問點按照dfn排序,再用乙個棧進行維護建樹。彈棧的時候並不是每個點都和棧中第二個元素連邊,有可能最後乙個彈棧點和新的lca連邊。dp轉移時需要查詢樹鏈的最...

SDOI2011 消耗戰 虛樹

有m次詢問,又有詢問的總的點數之和是小於等於5e5的,所以,其實就是乙個虛樹的模板了,直接用棧維護乙個虛樹即可。期間寫的時候出現了一點問題 初始化的時候,不只是要初始那些輸入的k個結點,還有k個結點的lca的衍生結點也是需要初始化的,所以初始化不到位會mle和tle的,這裡不要忘。include i...