●洛谷P2495 [SDOI2011]消耗战

题链:

https://www.luogu.org/problemnew/show/P2495
题解:

虚树入门,树形dp
推荐博客:http://blog.csdn.net/lych_cys/article/details/50814948

代码:

#include<bits/stdc++.h>
#define MAXN 250005
#define INFll 0x3f3f3f3f3f3f3f3fll
using namespace std;
int N,Q,M;
bool mark[MAXN];
long long val[MAXN];
int mincut[MAXN],dfn[MAXN],deep[MAXN],fa[MAXN][19];
struct Edge{
	int ent;
	int to[MAXN*2],val[MAXN*2],nxt[MAXN*2],head[MAXN];
	Edge(){ent=2;}
	void Adde(int u,int v,int w){
		to[ent]=v; val[ent]=w;
		nxt[ent]=head[u]; head[u]=ent++;
	}
}E1,E2;
bool cmp(int a,int b){return dfn[a]<dfn[b];}
void read(int &x){
	static int sign; static char ch;
	sign=1; x=0; ch=getchar();
	for(;ch<‘0‘||‘9‘<ch;ch=getchar()) if(ch==‘-‘) sign=-1;
	for(;‘0‘<=ch&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘;
	if(sign==-1) x=-x;
}
void dfs(int u,int dep){
	static int dnt;
	dfn[u]=++dnt; deep[u]=dep;
	for(int k=1;k<19;k++)
		fa[u][k]=fa[fa[u][k-1]][k-1];
	for(int e=E1.head[u];e;e=E1.nxt[e]){
		int v=E1.to[e]; if(v==fa[u][0]) continue;
		fa[v][0]=u; val[v]=min(val[u],1ll*E1.val[e]);
		dfs(v,dep+1);
	}
}
int LCA(int u,int v){
	if(deep[u]>deep[v]) swap(u,v);
	for(int k=18;k>=0;k--) if(deep[fa[v][k]]>=deep[u]) v=fa[v][k];
	if(u==v) return u;
	for(int k=18;k>=0;k--) if(fa[u][k]!=fa[v][k]) u=fa[u][k],v=fa[v][k];
	return fa[u][0];
}
long long dp(int u){
	if(!E2.head[u]) return val[u];
	long long tmp=0;
	for(int e=E2.head[u];e;e=E2.nxt[e]){
		int v=E2.to[e]; tmp+=dp(v);
	}
	E2.head[u]=0;
	if(mark[u]) return val[u];
	return min(tmp,val[u]);
}
void solve(){
	static int a[MAXN*2],stk[MAXN*2],top,lca;
	read(M); E2.ent=2; top=0;
	for(int i=1;i<=M;i++) read(a[i]),mark[a[i]]=1;
	//虚树的构建------------------------------------
	sort(a+1,a+M+1,cmp); stk[++top]=1;
	for(int i=1;i<=M;i++){
		lca=LCA(stk[top],a[i]);
		if(lca!=stk[top]) while(1){
			if(dfn[stk[top-1]]<=dfn[lca]){
				E2.Adde(lca,stk[top],0),top--;
				if(stk[top]!=lca) stk[++top]=lca;
				break;
			}
			E2.Adde(stk[top-1],stk[top],0),top--;
		}
		if(stk[top]!=a[i]) stk[++top]=a[i];
	}
	while(top>1) E2.Adde(stk[top-1],stk[top],0),top--;
	//-----------------------------------------------
	printf("%lld\n",dp(1));
	for(int i=1;i<=M;i++) mark[a[i]]=0;
}
int main(){
	read(N);
	for(int i=1,a,b,c;i<N;i++){
		read(a),read(b),read(c);
		E1.Adde(a,b,c); E1.Adde(b,a,c);
	}
	val[1]=INFll; dfs(1,1); read(Q);
	while(Q--) solve();
	return 0;
}

  

原文地址:https://www.cnblogs.com/zj75211/p/8552094.html

时间: 2024-11-09 05:50:17

●洛谷P2495 [SDOI2011]消耗战的相关文章

洛谷 P2495 [SDOI2011]消耗战

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

luogu P2495 [SDOI2011]消耗战

二次联通门 : luogu P2495 [SDOI2011]消耗战 /* luogu P2495 [SDOI2011]消耗战 虚树+树形dp 首先对原图构建出虚树 在建图的时候处理出最小值 转移即可 小技巧 在dp的过程中可以顺便把边表清空 将边结构体封装可方便的建多张图 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define INF 1

AC日记——[SDOI2011]消耗战 洛谷 P2495

[SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 #define maxn 250005 #define ll long long #define maxm (maxn<<1) struct LandType { ll id,key; bool operator<(const LandType pos)const { return key

洛谷 P2486 [SDOI2011]染色

题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#1: 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q 3 5 C 5 1 2 Q 3 5 输出样例#1: 3 1 2 说明 题目大意:给一棵树,要求支持链覆盖+查询链上颜色段数 先考虑链上怎么做吧,颜色段数这个东西支持区间加,一个区间可以用三个属性表示:左端点的颜色,右端点的颜色,区间颜色段数 两段合并以后的颜色段数是:左段颜色段数+右

洛谷 P2487 [SDOI2011]拦截导弹

题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小.也就是拦截导弹的数量最多的方案.但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案

洛谷 P2488 [SDOI2011]工作安排

题目描述 你的任务是制定出一个产品的分配方案,使得订单条件被满足,并且所有员工的愤怒值之和最小.由于我们并不想使用Special Judge,也为了使选手有更多的时间研究其他两道题目,你只需要输出最小的愤怒值之和就可以了. 输入输出格式 输入格式: 输出格式: 仅输出一个整数,表示最小的愤怒值之和. 输入输出样例 输入样例#1: 2 3 2 2 2 1 1 0 0 0 1 1 2 1 10 1 2 1 6 输出样例#1: 24 说明 一看,哇,修车,美食节,直接拆点,跑费用流,光荣T掉,还WA了

P2495 [SDOI2011]消耗战 虚树

这是我做的第一道虚树题啊,赶脚不错.其实虚树也没什么奇怪的,就是每棵树给你一些点,让你多次查询,但是我不想每次都O(n),所以我们每次针对给的点建一棵虚树,只包含这些点和lca,然后在这棵虚树上进行树形dp,维护每个点的最小连边权值,这样的复杂度就会降低不少.这里我写了两种写法(其实都是抄的),一种是正常建树的正常做法,还有一种是不用建树,只用堆维护,模拟一棵树的操作,维护欧拉序,就是一个点有进入的编号,也有出去的编号.这样就可以不用真正建出虚树而能进行查询. 题干: 题目描述 在一场战争中,战

P2495 [SDOI2011]消耗战

传送门 虚树DP经典题 首先有一个显然的$O(nm)$的树形DP 以 1 号节点为根 设 $f [ x ]$ 表示把节点 $x$ 子树内的资源点都与 $x$ 的父节点断开的最小代价 那么转移显然: 枚举 $x$ 的所有儿子节点 $v$,设 $x$ 到父节点的边权为 $w$ $f [ x ] = min ( w,\sum_vf[v] )$ 然后发现 $\sum_{k_i}\leq 500000$ 所以显然要搞虚树 每次DP只要把有用的节点提出来,根据它们之间的父子关系建一颗虚树 DP只要在虚树上D

洛谷 P2486 BZOJ 2243 [SDOI2011]染色

题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. 输入输出格式 输入格式: 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n个节点的初始颜色 下面 行每行包含两个整数x和y,表示x和y之间有一条无向边. 下面 行每行描述一个操作: “C a