https://www.luogu.com.cn/problem/P2495

虚树:当我们在解决树形dp的问题的时候,题目中会给出一些询问,询问涉及的关键节点不多,并保证总的点数规模的时候,我们就可以使用虚数,如果每次询问都对整个树进行dp的话,显然会超市。要注意每一次的初始化

题目:给出n点,有n-1条带权边,有q个询问,每次给出k个点,询问要使得这k个点和1号节点不连通,需要移除的边的总权值最小是多少。

思路:

令dp[n]表示从nn开始不能到达其子树中的关键点所需切断的最小边权和.

令me[u]表示切断11到uu的路径中的边权最小值.

设vv是uu的直接儿子.

如果vv是关键节点,那么dp[u]+=me[v],否则dp[u]+=min(me[v],dp[v])
(第2个转移方程的解释:要么直接切断1−v的路径,要么使得从v出发不能到达其子树的关键点.)

显然我们不能针对每个询问对整颗子树进行dpdp,时间复杂度过高,而我们发现那些非关键点我们没有必要在dp的时候考虑,所以使用虚树.

参考:大神题解

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <cstdlib>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define re register
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define rep(i,n) for(int i=0;(i)<(n);i++)
#define rep1(i,n) for(int i=1;(i)<=(n);i++)
#define se second
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define ac cout<<ans<<"\n"
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
using namespace std;
typedef long long  ll;
typedef unsigned long long  ull;
typedef pair<ll,ll> pii;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1};
const ll mod=1e9+7;
const ll N =250007;
const ll M =250000;
const double eps = 1e-4;
//const double pi=acos(-1);
ll qk(ll a,ll b){ll ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b/=2;}return ans%mod;}
int n;
int cnt,m;
int ldfn[N],rdfn[N];//当前节点的dfs序
int fa[N][20];//f[i][j]表示i节点向上2^j步的祖先
int dep[N];//节点深度
int stk[N];//栈,用于构建虚树
int d[N<<1];//用于存储虚树的节点编号。由于LCA可能有重复,因此需要开2倍
int vis[N];//标记当前节点是否为关键点
vector<pii> RG[N];
vector<int> VG[N];
ll me[N];
void predfs(int u,int f,int depth)
{ldfn[u]=++cnt;dep[u]=depth;fa[u][0]=f;for(int j=1;j<20;j++){fa[u][j]=fa[fa[u][j-1]][j-1];}for(pii k:RG[u]){int v=k.fi;if(v==f) continue;me[v]=k.second;if(u!=1) me[v]=min(me[u],me[v]);predfs(v,u,depth+1);}rdfn[u]=cnt;
}int lca(int u,int v)
{if(dep[u]<dep[v])swap(u,v);int delta=dep[u]-dep[v];for(int j=0;j<20&&delta;j++){if(delta&(1<<j))u=fa[u][j];}if(u==v) return u;for(int j=20-1;j>=0;j--){if(fa[u][j]!=fa[v][j]){u=fa[u][j];v=fa[v][j];}}return fa[u][0];
}bool cmp(int x,int y)
{return ldfn[x]<ldfn[y];
}void build()
{sort(d+1,d+m+1,cmp);int keynum=m;for(int i=1;i<keynum;i++) d[++m]=lca(d[i],d[i+1]);sort(d+1,d+m+1,cmp);m=unique(d+1,d+m+1)-d-1;int top=0;stk[++top]=d[1];for(int i=2;i<=m;i++){while(top&&rdfn[stk[top]]<ldfn[d[i]])top--;if(top)VG[stk[top]].push_back(d[i]);stk[++top]=d[i];}
}
ll DP(int u){ll cost=0;for(int v:VG[u]){cost+=min(me[v],DP(v));}VG[u].clear();//初始化if(vis[u]) return me[u];else return cost;
}
void sovle(){cin>>n;for(int i=1;i<n;i++){int u,v,c;cin>>u>>v>>c;RG[u].push_back({v,c});RG[v].push_back({u,c});}predfs(1,0,0);int q;cin>>q;while(q--){cin>>m;m++;d[1]=1;for(int i=2;i<=m;i++){cin>>d[i];vis[d[i]]=1;}build();cout<<DP(1)<<endl;for(int i=2;i<=m;i++) vis[d[i]]=0;//初始化部分很关键cnt=0;}
}
int main()
{
#ifdef LOCALfreopen("in.txt", "r", stdin);
#else// iosint t=1;// cin>>t;while(t--) sovle();
#endif // LOCALreturn 0;
}

P2495 [SDOI2011]消耗战-虚树+树形dp相关推荐

  1. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问, 每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接. 最少的边权和是多少. (n<=250000,sigma(ki)&l ...

  2. 洛谷 P2495 [SDOI2011]消耗战 虚树

    题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...

  3. P2495 [SDOI2011]消耗战 虚树入门

    一棵树,n个点m个操作.每条边有权值,每个操作给你k个点,问断开若干条边后使k个点与根不相连的最小边权和是多少. 有sigmaK<500000 易知一个裸的树dp需要复杂度,m次操作后总复杂度为 ...

  4. 「Luogu2495」 [SDOI2011]消耗战 虚树

    Luogu P2495 [SDOI2011]消耗战 problem Solution 苦思冥想稍作思考之后可以得到一个树形DP的方法: 令\(w(u,v)\)表示u,v之间的边的权值,\(f[u]\) ...

  5. [WC2018]通道——边分治+虚树+树形DP

    题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...

  6. BZOJ5341[Ctsc2018]暴力写挂——边分治+虚树+树形DP

    题目链接: CSTC2018暴力写挂 题目大意:给出n个点结构不同的两棵树,边有边权(有负权边及0边),要求找到一个点对(a,b)满足dep(a)+dep(b)-dep(lca)-dep'(lca)最 ...

  7. 洛谷_2495 [SDOI2011]消耗战(虚树)

    消耗战 题目链接:https://www.luogu.com.cn/problem/P2495 题解: 对于单样例,可以考虑树形DP. 但此题是多实例,所以需要对树进行处理,每次询问有k+1(加上一号 ...

  8. BZOJ5419[Noi2018]情报中心——线段树合并+虚树+树形DP

    题目链接: [NOI2018]情报中心 题目大意:给出一棵n个节点的树,边有非负边权,并给出m条链,对于每条链有一个代价,要求选出两条有公共边的链使两条链的并的边权和-两条链的代价和最大. 花了一天的 ...

  9. bzoj 3611: [Heoi2014]大工程(虚树+树形DP)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MB Submit: 1697  Solved: 718 [Submit][Stat ...

最新文章

  1. 那些进入 Alexa 排名前 250 的 WordPress 网站
  2. 借助 Subversion 进行版本控制
  3. java接口课程_用java定义一个接口,用于查询课程
  4. array python 交集_Python基础(二)——列表和元组
  5. 隔离 docker 容器中的用户-------分享链接
  6. 制作一个遍历当前子目录的Makefile
  7. 利用matlab描点绘制平滑曲线
  8. 学会提问pdf_原来只要1分钟,Word、PPT、PDF文件就能随意互相转换,快学学
  9. 画图工具轻松打印长图
  10. iphone个系列尺寸_10年巨变:华为手机是如何赶超iPhone的
  11. 将linux系统制作成iso镜像文件
  12. 010-lissajous(二)
  13. java exchange 日历_如何通过EWS-API 获取所有会议室的日历信息
  14. 虚拟机上部署Envoy Gateway:(一)创建虚拟机
  15. 华为linux系统安装包,一、Linux系统安装
  16. 利用html 和css模仿必应搜索主页。(一)
  17. 知识图谱入门学习笔记(一)-概念
  18. 第七篇:爬虫实战— 3、自动登录123并且自动发送邮箱;自动爬取京东商品信息...
  19. 《超算竞赛导引》笔记
  20. JavaSE【定制化】~ 基础篇

热门文章

  1. 数字音乐收费,一场困兽犹斗
  2. 实用的60个CSS代码片段[下]
  3. vba 窗体计时器 出现类型错误
  4. 国内移动应用开发平台哪家强?
  5. python判断正数还是负数_python判断正负数方式
  6. js实现字母序号自动递增
  7. 基于Python+django的网购平台购物商城-计算机毕业设计
  8. 临床医学中计算机的应用,临床医学中计算机图像处理技术的应用
  9. 因抢一个月饼,惨遭阿里开除,如今的他把生活过成这
  10. 直播电商购物消费者满意度在线调查报告(四)