2286: [Sdoi2011]消耗战

Time Limit: 20 Sec  Memory Limit: 512 MB

Submit: 4261  Solved: 1552

[Submit][Status][Discuss]

Description

在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。

Input

第一行一个整数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,表示资源丰富岛屿的编号。

Output

输出有m行,分别代表每次任务的最小代价。

Sample Input

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

Sample Output

12

32

22

HINT

对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

我一定要吐槽一下,神™c <= 100000,假的吧= =

我INF开了10^9都不够和c比,调了一中午对别人代码从头对到尾就是找不出错= =

MMP

唉,还是自己弱,刚学虚树,对建树过程不太自信

先说说树形dp,我们设f[i]表示i节点封锁的最小开销【我们把每条向上的边直接看做该点的权值】

则f[i] = min(v[i],∑f[to])

我们知道封锁父亲效果一定不比封锁儿子差,那么每个点u的权值可以看做v[u] = min(v[u的祖先们])、

直接做肯定T,O(mn),题目甚至直接都没有m的上限,而k的上限提醒我们只处理每次涉及到的点

如何抽出一棵树中单独的一些点呢?这就是虚树了

虚树

虚树,用来处理一棵有很多节点的树,询问只涉及其中部分节点且剩余节点的值对答案没有影响
这个时候我们只需保证树的形态不变,也就是询问点的相互位置关系不变,抽出来建一棵新的树,就是虚树

如何建树?
我们将所有点按照dfn排序,模拟递归的做法,开一个栈,表示当前正在处理以栈顶为根的子树
当我们遇到节点u时
①若u与栈顶p的lca就是p,说明u一定在p的子树内,由于是按照dfn顺序,那么接下来的节点就会在u的子树里,u入栈
②若u与栈顶p的lca不是p,那么一定在p之上,那么p的子树内的建树已经完成,不会再有里边的节点,而将处理lca为根的子树,这时候逐一出栈并建边,直至lca可以入栈的位置,lca入栈,u入栈

或者可以这么想,我们维护的栈实际上就是从根出发的一条链,由于按照dfs序,所以这条链按照一个方向延伸,当不能延伸的时候,前方已经没有了新的节点,链往回缩,缩的同时就把这些点给连边了,当缩到一个位置往另一边又有可以延伸的节点时,链继续延伸,最后所有点都到达,链往回缩回根。至此,所有的边都建好了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define PP(a,b) printf("link %d -> %d\n",a,b)
using namespace std;
const int maxn = 250005,maxm = 510005;
const LL INF = 100000000000000000ll;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int n,m,K,h[maxn],ne = 0,fa[maxn][20],dfn[maxn],dep[maxn],cnt = 0;
int s[maxn],t[maxn];
LL mn[maxn],f[maxn];
struct EDGE{int to,nxt; LL w;}ed[maxm];
inline void build(int u,int v,int w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
}
inline void add(int u,int v){if (u != v) {ed[ne] = (EDGE){v,h[u],0}; h[u] = ne++;}}
void dfs(int u,int ff,int d){
fa[u][0] = ff; dfn[u] = ++cnt; dep[u] = ++d;
Redge(u) if (ed[k].to != ff){
mn[ed[k].to] = min(mn[u],ed[k].w);
dfs(ed[k].to,u,d);
}
}
void init(){REP(j,19) REP(i,n) fa[i][j] = fa[fa[i][j - 1]][j - 1];}
int lca(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
int d = dep[u] - dep[v];
for (int i = 0; (1 << i) <= d; i++)
if (d & (1 << i)) u = fa[u][i];
for (int i = 19; i >= 0; i--)
if (fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
if (u == v) return u;
return fa[u][0];
}
inline bool cmp(const int& a,const int& b){return dfn[a] < dfn[b];}
void rebuild(){
int top,tot = 0; s[top = 1] = 1; ne = 0;
sort(t + 1,t + 1 + K,cmp); t[++tot] = t[1];
for (int i = 2 ; i <= K; i++) if (lca(t[i],t[tot]) != t[tot]) t[++tot] = t[i];
for (int i = 1; i <= tot; i++){
int u = t[i],v = lca(u,s[top]);
while (true){
if (dep[v] >= dep[s[top - 1]]){
add(v,s[top--]); if (v != s[top]) s[++top] = v;
break;
}
add(s[top - 1],s[top]); top--;
}
if (s[top] != u) s[++top] = u;
}
while (--top) add(s[top],s[top + 1]);
}
void dp(int u){
f[u] = mn[u]; LL tmp = 0;
Redge(u) dp(ed[k].to),tmp += f[ed[k].to];
h[u] = -1;
if (tmp == 0) f[u] = mn[u];
else if (tmp <= f[u]) f[u] = tmp;
}
void solve(){
K = RD(); REP(i,K) t[i] = RD();
rebuild(); dp(1);
printf("%lld\n",f[1]);
}
int main(){
memset(h,-1,sizeof(h));
n = RD(); int a,b,w;
for (int i = 1; i < n; i++) a = RD(),b = RD(),w = RD(),build(a,b,w);
mn[1] = INF; dfs(1,0,0); init();
REP(i,n) h[i] = -1;
m = RD(); while (m--) solve();
return 0;
}

最新文章

  1. [Spring MVC] - 500/404错误处理
  2. Docker之Linux UnionFS
  3. ecshop /goods.php SQL Injection Vul
  4. 34款Firefox渗透测试插件工具
  5. Qt make clickable label 制作可点击的Label控件
  6. python编写接口
  7. PagerAdapter的notifyDataSetChanged无效解决方法
  8. 【Linux/Ubuntu学习 7】E: 无法获得锁 /var/lib/dpkg/lock – open (11: 资源暂时不可用) E: 无法锁定管理目录
  9. jQuery队列控制方法详解queue()/dequeue()/clearQueue()
  10. 一种轻量的openresty路由设计
  11. 在world中批量调整图片的大小
  12. 提示框插件SweetAlert
  13. cocos2dx工程
  14. HDU-5157Harry and magic string
  15. [Swift]LeetCode317. 建筑物的最短距离 $ Shortest Distance from All Buildings
  16. 数据库訪问技术之JDBC
  17. KVM虚拟化管理 virt manager常用操作
  18. 由异常掉电问题---谈xfs文件系统
  19. python stdout 重定向
  20. BZOJ 2648 SJY摆棋子(KD树)

热门文章

  1. sublime3常用插件总结
  2. 官方yum源安装选择所需版本mysql数据库并初始化(yum默认安装的是最新版MySQL8.+)
  3. 网站安全检测 漏洞检测 对thinkphp通杀漏洞利用与修复建议
  4. shell重温---基础篇(函数操作)
  5. ionic 打包apk Failure [INSTALL_FAILED_USER_RESTRICTED: Install canceled by user]
  6. 浅析 Linux 初始化 init 系统,Systemd
  7. QC的使用学习(二)
  8. javaX邮件发送
  9. (原) MatEditor部- UmateriaEditor中Texture使用过程(1)
  10. Floatingip