https://www.lydsy.com/JudgeOnline/problem.php?id=2286

wa了两次因为lca犯了zz错误

这道题如果不多次询问的话就是裸dp。

一棵树上多次询问,且总共询问的点数较小(能够承受得住加个logn的复杂度(常数就不管了,按理说还要*2吧))可以用虚树来处理。

虚树就是对每次询问将有用的点建一棵树,每次询问查询m个点,则这棵树最多m*2个点(太优秀了)。

这个虚树的建立过程是用栈维护一条链,每加入一个点就把她和前一条链的叶子节点的lca和这个点本身加入虚树中,然后将当前链的叶子节点改为当前加入的点。

dfs序是个好东西,它帮助维护了这条链和后面点的关系(的逻辑性?(看到代码就懂了吧,反正就很有逻辑就对了))。

所以我之前为什么要学树链剖分,树链剖分什么用都没有嘤嘤嘤,最喜欢倍增了。(日常抛弃旧爱)

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
const int maxn=;
const LL minf=(LL)5e17;
int n,m;
struct nod{
int nex,y,v;
};nod e[maxn*];nod e1[maxn*];
int head[maxn]={},tot=;
int head1[maxn]={},tot1=;
int id[maxn]={},cnt=;
int fa[maxn][]={},dep[maxn]={};
LL dis[maxn]={},f[maxn]={};
int a[maxn]={},tly=;
int sta[maxn]={},tai=;
inline int mread(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void init(int x,int y,int v){
e[++tot].y=y;e[tot].v=v;e[tot].nex=head[x];head[x]=tot;
}
inline void init1(int x,int y){
if(x==y)return;
e1[++tot1].y=y;e1[tot1].nex=head1[x];head1[x]=tot1;
}
void dfs(int x,int pa){
fa[x][]=pa;id[x]=++cnt;
for(int i=;fa[fa[x][i-]][i-]!=;++i)fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=e[i].nex){
int y=e[i].y;
if(y==pa)continue;
dis[y]=dis[x]<e[i].v?dis[x]:e[i].v;
dep[y]=dep[x]+;
dfs(y,x);
}
}
bool mcmp(int x,int y){return id[x]<id[y];}
int getlca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=;i>=;--i){
if(!fa[x][i])continue;
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(dep[x]==dep[y])break;
}
if(x==y)return x;
for(int i=;i>=;--i){
if(!fa[x][i])continue;
if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}
}
return fa[x][];
}
void dfs1(int x){
f[x]=dis[x];LL v=;
for(int i=head1[x];i;i=e1[i].nex){
dfs1(e1[i].y);
v+=f[e1[i].y];
}
if(v)f[x]=min(f[x],v);
head1[x]=;
}
void cutit(){
int q=mread(); for(int i=;i<=q;++i)a[i]=mread();
sort(a+,a++q,mcmp); tly=;
for(int i=;i<=q;++i){if(getlca(a[i],a[tly])!=a[tly])a[++tly]=a[i];}
//由根节点到叶子节点的每条链上至多只有一个点
tai=;sta[]=;tot1=;int lc;
for(int i=;i<=tly;i++){//sta按照dfs序维护了一条链
lc=getlca(sta[tai],a[i]);
for(;tai>;){//更改链向下延伸的方向,把之前方向的点连上
if(dep[sta[tai-]]<=dep[lc]){
init1(lc,sta[tai]);tai--;
if(sta[tai]!=lc)sta[++tai]=lc;
break;
}init1(sta[tai-],sta[tai]);tai--;
}
if(sta[tai]!=a[i])sta[++tai]=a[i];
}
while(--tai)init1(sta[tai],sta[tai+]);
dfs1();
printf("%lld\n",f[]);
}
int main(){
int x,y,v;
n=mread();
for(int i=;i<n;++i){
x=mread();y=mread();v=mread();
init(x,y,v);init(y,x,v);
}
dis[]=minf; dep[]=; dfs(,);
m=mread(); for(int i=;i<=m;++i) cutit();
return ;
}

BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序的更多相关文章

  1. BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)

    题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...

  2. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  3. bzoj 2286 [Sdoi2011]消耗战 虚树+dp

    题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...

  4. BZOJ 2286: [Sdoi2011]消耗战 虚树

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

  5. BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)

    Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5246  Solved: 1978[Submit][Status][Discuss] Descript ...

  6. BZOJ 2286 [Sdoi2011]消耗战 ——虚树

    虚树第一题. 大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP #include <map> #include <ctime> #include <cmath&g ...

  7. 【BZOJ-2286】消耗战 虚树 + 树形DP

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status] ...

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

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

  9. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

随机推荐

  1. UNIX环境高级编程 第13章 守护进程

    守护进程daemon是一种生存周期很长的进程.它们通常在系统引导时启动,在系统关闭时终止.守护进程是没有终端的,它们一直在后台运行. 守护进程的特征 在Linux系统中,可以通过命令 ps -efj ...

  2. jq 监听input值的变化

    $(".popWeiXing .name").bind("input propertychange", function() { modValue.diyDat ...

  3. go 切片

    切片定义 切片是基于数组类型做的一层封装.它非常灵活,可以自动扩容. var a []int //定义一个int类型的空切片 切片初始化, a[start:end]创建一个包括从start到end-1 ...

  4. XSS注入常用语句

    <script>alert('hello,gaga!');</script> //经典语句,哈哈! >"'><img src="javas ...

  5. 乐视mysql面试题【转】

    最近,朋友去乐视面试了mysql DBA,以下是我据整理的乐视mysql面试题答案,供大家参考 1. MYISAM和INNODB的不同?答:主要有以下几点区别:   a)构造上的区别     MyIS ...

  6. Python的日志记录-logging模块的使用

    一.日志 1.1什么是日志 日志是跟踪软件运行时所发生的事件的一种方法,软件开发者在代码中调用日志函数,表明发生了特定的事件,事件由描述性消息描述,同时还包含事件的重要性,重要性也称为级别或严重性. ...

  7. 数据库-mysql中文显示问题

    一:在mysql 下面查看带中文的记录显示乱码 mysql> select * from role; +----+------+ | id | name | +----+------+ | 1 ...

  8. Nginx - keepliave 相关知识点

    目录 - 1. 前言- 2. keepalive 介绍- 3. Nginx 与 keepalive 的关系    - 3.1 Nginx - keepalive_timeout    - 3.2 Ng ...

  9. thinkphp辅助方法,数据库操作

  10. js中的call,apply,bind区别

    在JavaScript中,call.apply和bind是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向. call.apply.bind方法的共同点和区别:app ...