這是我做的第一道虛樹題啊,趕腳不錯.其實虛樹也沒什麼奇怪的,就是每棵樹給你一些點,讓你多次查詢,但是我不想每次都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...