题面

本身求答案是简单的树上DP,只需要求出根到每个点路径上的最小值,然后考虑割连父亲的边还是割所有儿子即可,但是每次都这样做一次显然不能通过,考虑优化

用虚树来优化:虚树是针对树上一些点建出来的一棵树,上面只有这些点和它们的LCA。显然这样虚树的大小不会超过2*所选点数,这样在缩小了问题规模的同时还保留了原树的性质。

具体的建法:

0.预处理DFS序

1.将所选点按DFS序从小到大排序

2.用栈维护一条从根延伸下来的链,依次将排序后的点nde加入。若栈为空则直接入栈,否则设栈顶为top:

3.求nde和top的lca,讨论:

①lca是top,将nde入栈,跑路

②lca不是top,设栈顶起第二个元素为sec。在lca的DFS序不大于sec时不断将sec与top相连并弹栈

(1)如果lca的DFS序小于top,将lca与top相连,弹栈

(2)如果lca仍然不是top,将lca入栈

(3)将nde入栈

(因为我们按DFS序排序,所以lca不可能是nde)

4.将所有点加入后,不断将sec与top相连并弹栈,直到栈里只有一个元素,这就是虚树的树根

之后就可以愉快地树形DP辣

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int T,n,m,t1,t2,t3,cnt,Cnt,tot,poi;
int P[N],Noww[N],Goal[N],p[N],noww[N],goal[N],val[N],cut[N];
int siz[N],far[N],dep[N],imp[N],top[N],dfn[N],pts[N],stk[N];
long long mini[N];
bool cmp(int a,int b)
{
return dfn[a]<dfn[b];
}
void Link(int f,int t,int v)
{
noww[++cnt]=p[f],p[f]=cnt;
goal[cnt]=t,val[cnt]=v;
noww[++cnt]=p[t],p[t]=cnt;
goal[cnt]=f,val[cnt]=v;
}
void Linka(int f,int t)
{
Noww[++Cnt]=P[f];
Goal[Cnt]=t,P[f]=Cnt;
}
void DFS(int nde,int fth,int dth)
{
int tmp=;
siz[nde]=,far[nde]=fth,dep[nde]=dth;
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth)
{
mini[goal[i]]=min(mini[nde],1ll*val[i]);
DFS(goal[i],nde,dth+);
siz[nde]+=siz[goal[i]];
if(siz[goal[i]]>tmp)
tmp=siz[goal[i]],imp[nde]=goal[i];
}
}
void Mark(int nde,int tpp)
{
top[nde]=tpp,dfn[nde]=++tot;
if(imp[nde])
{
Mark(imp[nde],tpp);
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=far[nde]&&goal[i]!=imp[nde])
Mark(goal[i],goal[i]);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y); x=far[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void Insert(int nde)
{
if(!poi) stk[++poi]=nde;
else
{
int lca=LCA(nde,stk[poi]);
if(lca!=stk[poi])
{
while(poi>&&dfn[lca]<=dfn[stk[poi-]])
Linka(stk[poi-],stk[poi]),poi--;
if(dfn[lca]<dfn[stk[poi]])
Linka(lca,stk[poi]),poi--;
if(lca!=stk[poi])
stk[++poi]=lca;
}
stk[++poi]=nde;
}
}
long long Getans(int nde)
{
long long tmp=;
for(int i=P[nde];i;i=Noww[i])
tmp+=Getans(Goal[i]); P[nde]=;
return cut[nde]?mini[nde]:min(mini[nde],tmp);
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%d%d%d",&t1,&t2,&t3),Link(t1,t2,t3);
for(int i=;i<=n;i++) mini[i]=1e12;
DFS(,,),Mark(,);
scanf("%d",&T);
while(T--)
{
scanf("%d",&m),Cnt=poi=;
for(int i=;i<=m;i++) scanf("%d",&pts[i]);
sort(pts+,pts++m,cmp);
for(int i=;i<=m;i++) Insert(pts[i]),cut[pts[i]]=true;
while(poi>) Linka(stk[poi-],stk[poi]),poi--;
printf("%lld\n",Getans(stk[]));
for(int i=;i<=m;i++) cut[pts[i]]=false;
}
return ;
}

解题:SDOI 2011 消耗战的更多相关文章

  1. [bzoj2286][Sdoi 2011]消耗战

    [bzoj2286]消耗战 标签: 虚树 DP 题目链接 题解 很容易找出\(O(mn)\)的做法. 只需要每次都dp一遍. 但是m和n是同阶的,所以这样肯定会T的. 注意到dp的时候有很多节点是不需 ...

  2. [SDOI 2011]消耗战

    Description 题库链接 给你一棵 \(n\) 个节点根节点为 \(1\) 的有根树,有边权. \(m\) 次询问,每次给出 \(k_i\) 个关键点.询问切断一些边,使这些点到根节点不连通, ...

  3. 解题: SDOI 2011 染色

    题面 强行把序列问题通过树剖套在树上...算了算是回顾了一下树剖的思想=.= 每次树上跳的时候注意跳的同时维护当前拼出来的左右两条链的靠上的端点,然后拼起来的时候讨论一下拼接点,最后一下左右两边的端点 ...

  4. 【codevs 1565】【SDOI 2011】计算器 快速幂+拓展欧几里得+BSGS算法

    BSGS算法是meet in the middle思想的一种应用,参考Yveh的博客我学会了BSGS的模版和hash表模板,,, 现在才会hash是不是太弱了,,, #include<cmath ...

  5. [BZOJ 2243] [SDOI 2011] 染色 【树链剖分】

    题目链接:BZOJ - 2243 题目分析 树链剖分...写了200+行...Debug了整整一天+... 静态读代码读了 5 遍 ,没发现错误,自己做小数据也过了. 提交之后全 WA . ————— ...

  6. BZOJ 2243 SDOI 2011染色

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 算法讨论: 树链剖分把树放到线段树上.然后线段树的每个节点要维护的东西有左端点的颜色 ...

  7. [SDOI 2011]黑白棋

    Description 题库链接 给出一个 \(1\times n\) 的棋盘,棋盘上有 \(k\) 个棋子,一半是黑色,一半是白色.最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 \( ...

  8. [SDOI 2011]染色

    Description 题库链接 给定一棵有 \(n\) 个节点的无根树和 \(m\) 个操作,操作有 \(2\) 类: 将节点 \(a\) 到节点 \(b\) 路径上所有点都染成颜色 \(c\) : ...

  9. [SDOI 2011]计算器

    Description 你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数: 3.给 ...

随机推荐

  1. 20155232《网络对抗》Exp8 Web基础

    20155232<网络对抗>Exp 8 Web基础 一.实践内容 (1).Web前端HTML(0.5分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编 ...

  2. mfc CCombox系统定义成员函数

    通过ID操作对象 CComboBox(组合框)控件 CComboBox类常用成员 CComboBox插入数据 CComboBox删除数据 CComboBox运用示例 一.CComboBox控件常用属性 ...

  3. dubbo见解

    调用关系说明 服务容器负责启动,加载,运行服务提供者. 服务提供者在启动时,向注册中心注册自己提供的服务. 服务消费者在启动时,向注册中心订阅自己所需的服务. 注册中心返回服务提供者地址列表给消费者, ...

  4. linux systemctl 命令

    目录 预热 管理单个 unit 查看系统上的 unit 管理不同的操作环境(target unit) 检查 unit 之间的依赖性 相关的目录和文件 systemctl daemon-reload 子 ...

  5. 矩阵分解----Cholesky分解

    矩阵分解是将矩阵拆解成多个矩阵的乘积,常见的分解方法有 三角分解法.QR分解法.奇异值分解法.三角分解法是将原方阵分解成一个上三角矩阵和一个下三角矩阵,这种分解方法叫做LU分解法.进一步,如果待分解的 ...

  6. java算法面试题

    前言:线上面试题与大家分享,并记录求职道路的酸甜苦辣,特此留念. 李雷和韩梅梅坐前后排,上课想说话怕被老师发现,所以改为传小纸条.为了不被老师发现他们纸条上说的是啥,他们约定了如下方法传递信息:将26 ...

  7. [算法总结] 6 道题搞定 BAT 面试——堆栈和队列

    本文首发于我的个人博客:尾尾部落 0. 基础概念 栈:后进先出(LIFO) 队列:先进先出(FIFO) 1. 栈的 java 实现 import java.util.Arrays; public cl ...

  8. X32位 天堂2 二章/三章 服务端协议号修改方法

    [本方法适合于2004-2006年之间天堂2由初章服务端修改至二章.三章端时协议号匹配问题]服务端版本位32位初章服务端 目前大部分SF用的协议号情况: 服务端是419 客户端是 417 419 42 ...

  9. 镜像仓库管理:与Portus不得不说的那些事

    背景: 目前在做一个云计算相关的项目,其中有这样一个需求:每个平台用户都有自己的docker镜像仓库(docker registry),用户可以对自己的镜像仓库的push/pull权限进行管理,也就是 ...

  10. Linux_02

    1.vim编辑器 vim操作命令 --在命令模式下进行 pageup 往上翻页 pagedown 往下翻页 H 移动到屏幕首行 gg 移动光标到文档的首行 前面加数字n表示移动到n行内容 G 移动到文 ...