标签:输入格式 dig == 返回 dep new 直接 opera 机器
在一场战争中,战场由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行,分别代表每次任务的最小代价。
10
1 5 13
1 9 6
2 1 19
2 4 8
2 3 91
5 6 8
7 5 4
7 8 31
10 7 9
3
2 10 6
4 5 7 8 3
3 9 4 6
12
32
22
对于10%的数据,2<=n<=10,1<=m<=5,1<=ki<=n-1
对于20%的数据,2<=n<=100,1<=m<=100,1<=ki<=min(10,n-1)
对于40%的数据,2<=n<=1000,m>=1,sigma(ki)<=500000,1<=ki<=min(15,n-1)
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
struct node {
int to;
LL dis;
node *nxt;
node(int to = 0, LL dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {}
void *operator new (size_t) {
static node *S = NULL, *T = NULL;
return (S == T) && (T = (S = new node[1024]) + 1024), S++;
}
};
const int maxn = 2e5 + 6e4;
const LL inf = 999999999999999LL;
node *head[maxn], *h[maxn];
int dep[maxn], f[maxn][28], a[maxn], st[maxn], top, g[maxn], dfn[maxn];
LL d[maxn][28], dp[maxn];
int n, m, cnt;
bool is[maxn];
void add(int from, int to, LL dis, node **hh) {
hh[from] = new node(to, dis, hh[from]);
}
void dfs(int x, int fa) {
dfn[x] = ++cnt;
f[x][0] = fa;
dep[x] = dep[fa] + 1;
for(node *i = h[x]; i; i = i->nxt)
if(i->to != fa) dfs(i->to, x), d[i->to][0] = i->dis;
}
void LCA(int x, int y, LL &dis, int &id) {
id = 0;
dis = inf;
if(dep[x] < dep[y]) std::swap(x, y);
for(int i = 26; i >= 0; i--) if(dep[f[x][i]] >= dep[y]) dis = std::min(dis, d[x][i]), x = f[x][i];
if(x == y) return (void)(id = x);
for(int i = 26; i >= 0; i--) if(f[x][i] != f[y][i]) dis = std::min(dis, std::min(d[x][i], d[y][i])), x = f[x][i], y = f[y][i];
dis = std::min(dis, std::min(d[x][0], d[y][0]));
id = f[x][0];
}
void DP(int x) {
if(is[x]) return (void)(dp[x] = inf);
dp[x] = 0;
for(node *i = head[x]; i; i = i->nxt)
DP(i->to), dp[x] += std::min(dp[i->to], i->dis);
}
void clr(int x) {
for(node *i = head[x]; i; i = i->nxt)
clr(i->to);
head[x] = NULL;
}
int main() {
n = in();
int x, y, z;
for(int i = 1; i < n; i++) {
x = in(), y = in(), z = in();
add(x, y, z, h), add(y, x, z, h);
}
memset(d, 0x7f, sizeof d);
dfs(1, 0);
for(int j = 1; j <= 26; j++)
for(int i = 1; i <= n; i++) {
f[i][j] = f[f[i][j - 1]][j - 1];
d[i][j] = std::min(d[i][j - 1], d[f[i][j - 1]][j - 1]);
}
for(m = in(); m --> 0;) {
int num = in();
for(int i = 1; i <= num; i++) a[i] = in(), is[a[i]] = true;
a[++num] = 1;
cnt = 0;
std::sort(a + 1, a + num + 1, [](const int &x, const int &y) { return dfn[x] < dfn[y]; });
st[top = 1] = a[1];
LL D;
int lca, id;
for(int i = 2; i <= num; i++) {
int now = a[i];
LCA(now, st[top], D, lca);
while(top > 1 && dep[lca] <= dep[st[top - 1]]) {
LCA(st[top], st[top - 1], D, id);
add(st[top - 1], st[top], D, head);
top--;
}
if(lca != st[top]) {
LCA(st[top], lca, D, id);
add(lca, st[top], D, head);
st[top] = lca;
}
st[++top] = now;
}
while(top > 1) {
LCA(st[top], st[top - 1], D, id);
add(st[top - 1], st[top], D, head);
top--;
}
DP(st[1]);
printf("%lld\n", dp[st[1]]);
clr(st[1]);
for(int i = 1; i <= num; i++) is[a[i]] = false;
}
return 0;
}
标签:输入格式 dig == 返回 dep new 直接 opera 机器
原文地址:https://www.cnblogs.com/olinr/p/10233909.html