zoukankan      html  css  js  c++  java
  • 【洛谷P2495】消耗战

    题目

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

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

    (2leq n leq 2.5 imes 10^5, 1leq mleq 5 imes 10^5, sum k_i leq 5 imes 10^5, 1leq k_i< n, h_i eq 1, 1leq u,vleq n, 1leq wleq 10^5)

    思路

    由于 (sum k_ileq 5 imes 10^5),考虑建立虚树。同时用倍增处理出虚树中每一条边所对应原图中的若干边的最小边权。
    然后直接树形 dp 即可。设 (h[x]) 表示以 (x) 为根的子树中,所有关键点与 (x) 的父亲不连通的最小代价。
    显然有

    [h[x]=min(dis_{fa,x},sum_{yin operatorname{son}(x)}h[y]) ]

    时间复杂度 (O((n+m)log n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=250010,LG=20;
    int n,m,Q,tot,a[N],head[N],dep[N],dfn[N],f[N][LG+1],g[N][LG+1];
    ll h[N];
    bool key[N];
    map<int,bool> vis;
    
    struct edge
    {
    	int next,to;
    	ll dis;
    }e[N*2];
    
    bool cmp(int x,int y)
    {
    	return dfn[x]<dfn[y];
    }
    
    void add(int from,int to,int dis)
    {
    	e[++tot].to=to;
    	e[tot].dis=dis;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs1(int x,int fa,int id)
    {
    	dep[x]=dep[fa]+1; dfn[x]=++tot;
    	f[x][0]=fa; g[x][0]=e[id].dis;
    	for (int i=1;i<=LG;i++)
    	{
    		f[x][i]=f[f[x][i-1]][i-1];
    		g[x][i]=min(g[x][i-1],g[f[x][i-1]][i-1]);
    	}
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (v!=fa) dfs1(v,x,i);
    	}
    }
    
    int lca(int x,int y)
    {
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=LG;i>=0;i--)
    		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=LG;i>=0;i--)
    		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    
    int getdis(int x,int y)
    {
    	int mind=2e9; 
    	for (int i=LG;i>=0;i--)
    		if (dep[f[x][i]]>=dep[y])
    		{
    			mind=min(mind,g[x][i]);
    			x=f[x][i];
    		}
    	return mind;
    }
    
    void build()
    {
    	stack<int> st;
    	st.push(1); head[1]=-1;
    	tot=0;
    	sort(a+1,a+1+m,cmp);
    	for (int i=1;i<=m;i++)
    	{
    		int p=lca(st.top(),a[i]);
    		while (dep[st.top()]>dep[p])
    		{
    			int x=st.top(); st.pop();
    			if (dep[st.top()]>=dep[p])
    				add(st.top(),x,getdis(x,st.top()));
    			else
    			{
    				if (!vis[p]) head[p]=-1,vis[p]=1;
    				add(p,x,getdis(x,p));
    			}
    		}
    		if (st.top()!=p) st.push(p);
    		st.push(a[i]);
    	}
    	while (st.top()>1)
    	{
    		int x=st.top(); st.pop();
    		add(st.top(),x,getdis(x,st.top()));
    	}
    }
    
    void dfs2(int x,int id)
    {
    	h[x]=e[id].dis;
    	if (key[x]) return;
    	ll sum=0;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		dfs2(v,i);
    		sum+=h[v];
    	}
    	h[x]=min(h[x],sum);
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	memset(g,0x3f3f3f3f,sizeof(g));
    	scanf("%d",&n);
    	for (int i=1,x,y,z;i<n;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z); add(y,x,z);
    	}
    	tot=0; e[0].dis=1e18;
    	dfs1(1,0,0);
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		scanf("%d",&m);
    		for (int i=1;i<=m;i++)
    		{
    			scanf("%d",&a[i]);
    			key[a[i]]=1; head[a[i]]=-1; vis[a[i]]=1;
    		}
    		build();
    		dfs2(1,0);
    		printf("%lld
    ",h[1]);
    		for (int i=1;i<=m;i++) key[a[i]]=0;
    		vis.clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux软件安装方式
    docker 安装 jenkins touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
    [ERR] Node goodsleep.vip:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
    Linux 常用命令 服务器间scp 用户 export 创建文件、软连接
    redis 安装 集群 主从 哨兵 docker
    WPF密码框中禁止复制、粘贴
    Application 统计在线人数
    【转义字符】HTML 字符实体&lt; &gt: &amp;等
    SQL语句统计每天的数据
    正则表达式计算代码数
  • 原文地址:https://www.cnblogs.com/stoorz/p/14006851.html
Copyright © 2011-2022 走看看