2514. 消耗战

题目链接

2514. 消耗战

[SDOI2011] 消耗战

题目描述

在一场战争中,战场由 n 个岛屿和 n1 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 1 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 k 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 1 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 m 次,所以我们只需要把每次任务完成即可。

输入格式

第一行一个整数 n,表示岛屿数量。

接下来 n1 行,每行三个整数 u,v,w ,表示 u 号岛屿和 v 号岛屿由一条代价为 w 的桥梁直接相连。

n+1 行,一个整数 m ,代表敌方机器能使用的次数。

接下来 m 行,第 i 行一个整数 ki ,代表第 i 次后,有 ki 个岛屿资源丰富。接下来 ki 个整数 h1,h2,...,hki ,表示资源丰富岛屿的编号。

输出格式

输出共 m 行,表示每次任务的最小代价。

样例 #1

样例输入 #1

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

样例输出 #1

12 32 22

提示

数据规模与约定

  • 对于 10% 的数据,n10,m5
  • 对于 20% 的数据,n100,m100,1ki10
  • 对于 40% 的数据,n1000,1ki15
  • 对于 100% 的数据,2n2.5×105,1m5×105,ki5×105,1ki<n,hi1,1u,vn,1w105

解题思路

虚树

考虑一般情况:

  • 状态表示:f[i] 表示将 i 为根节点的子树的所有查询点到 i 不连通的最少代价

  • 状态计算:ji 的儿子节点,wij 的最少代价

    • j 是查询节点,f[i]+=w
    • j 不是查询节点,f[i]+=min(w,f[j])

对于每次查询建立相应的虚树即可

  • 时间复杂度:O(nlogn)

代码

// Problem: 消耗战 // Contest: AcWing // URL: https://www.acwing.com/problem/content/2516/ // Memory Limit: 128 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=2.5e5+5; int n,m,k,a[N],f[N][20],mn[N][20],dep[N],dfn[N],cnt,t,dis; LL dp[N]; int stk[N],top; vector<PII> adj[N]; bool v[N]; void dfs(int x,int fa) { dfn[x]=++cnt; f[x][0]=fa; for(int i=1;i<=t;i++) f[x][i]=f[f[x][i-1]][i-1],mn[x][i]=min(mn[x][i-1],mn[f[x][i-1]][i-1]); for(auto &t:adj[x]) { int y=t.fi,w=t.se; if(y==fa)continue; dep[y]=dep[x]+1; mn[y][0]=w; dfs(y,x); } } int lca(int x,int y) { dis=1e9; if(dep[x]>dep[y])swap(x,y); for(int i=t;i>=0;i--) if(dep[f[y][i]]>=dep[x]) { dis=min(dis,mn[y][i]); y=f[y][i]; } if(x==y)return x; for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) { x=f[x][i],y=f[y][i]; dis=min({dis,mn[x][i],mn[y][i]}); } return f[x][0]; } bool cmp(int &x,int &y) { return dfn[x]<dfn[y]; } void build() { sort(a+1,a+1+k,cmp); stk[top=1]=1,adj[1].clear(); for(int i=1;i<=k;i++) if(a[i]!=1) { int l=lca(a[i],stk[top]); if(l!=stk[top]) { while(dfn[l]<dfn[stk[top-1]]) { int u=stk[top-1],v=stk[top]; lca(u,v); adj[u].pb({v,dis}); top--; } if(dfn[l]>dfn[stk[top-1]]) { adj[l].clear(); lca(l,stk[top]); adj[l].pb({stk[top],dis}); stk[top]=l; } else { lca(l,stk[top]); adj[l].pb({stk[top--],dis}); } } adj[a[i]].clear(),stk[++top]=a[i]; } for(int i=1;i<top;i++) { int u=stk[i],v=stk[i+1]; lca(u,v); adj[u].pb({v,dis}); } } void dfs(int x) { dp[x]=0; for(auto &t:adj[x]) { int y=t.fi,w=t.se; dfs(y); if(v[y])dp[x]+=w,v[y]=false; else dp[x]+=min(1ll*w,dp[y]); } } int main() { help; cin>>n; t=__lg(n); for(int i=1;i<n;i++) { int u,v,w; cin>>u>>v>>w; adj[u].pb({v,w}),adj[v].pb({u,w}); } dep[1]=1; dfs(1,0); cin>>m; while(m--) { cin>>k; for(int i=1;i<=k;i++)cin>>a[i],v[a[i]]=true; build(); dfs(1); cout<<dp[1]<<'\n'; } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16528029.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示

喜欢请打赏

扫描二维码打赏

支付宝打赏