ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2514. 消耗战

2022-07-28 11:35:03  阅读:115  来源: 互联网

标签:10 int top stk leq 消耗战 2514 adj


题目链接

2514. 消耗战

[SDOI2011] 消耗战

题目描述

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

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

输入格式

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

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

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

接下来 \(m\) 行,第 \(i\) 行一个整数 \(k_i\) ,代表第 \(i\) 次后,有 \(k_i\) 个岛屿资源丰富。接下来 \(k_i\) 个整数 \(h_1,h_2,..., h_{k_i}\) ,表示资源丰富岛屿的编号。

输出格式

输出共 \(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\%\) 的数据,\(n\leq 10, m\leq 5\) 。
  • 对于 \(20\%\) 的数据,\(n\leq 100, m\leq 100, 1\leq k_i\leq 10\) 。
  • 对于 \(40\%\) 的数据,\(n\leq 1000, 1\leq k_i\leq 15\) 。
  • 对于 \(100\%\) 的数据,\(2\leq n \leq 2.5\times 10^5, 1\leq m\leq 5\times 10^5, \sum k_i \leq 5\times 10^5, 1\leq k_i< n, h_i\neq 1, 1\leq u,v\leq n, 1\leq w\leq 10^5\) 。

解题思路

虚树

考虑一般情况:

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

  • 状态计算:\(j\) 为 \(i\) 的儿子节点,\(w\) 为 \(i\) 到 \(j\) 的最少代价

    • \(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;
}

标签:10,int,top,stk,leq,消耗战,2514,adj
来源: https://www.cnblogs.com/zyyun/p/16528029.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有