学习了一下虚树,讲一下自己的理解。

虚树是这么一个东西,对于需要求答案的点p,只保留对答案有影响的节点,从而减少时间。

现在对于这道题目进行特定的说明。

考虑朴素的dp,显然,dp[i]=min(val[i],Σdp[j](j为i的儿子)),val[i]表示将i和根节点分离的代价。那么这样的时间复杂度为O(N),总时间复杂度O(NM)。

注意题目中有Σk<=500000,因此如果能将一次的时间复杂度减小到O(K)或者O(KlogK),就能通过了。因此,关键是能构造出一颗节点<=O(K)级别的虚树,以及能在O(K)或者O(KlogK)的时间构造出虚树。

定义某一次询问给出的岛屿为关键点。注意到对于某对关键点(x,y),考虑x->lca(x,y)的路径中,没有那个点是某一对关键点的lca,那么显然x->lca(x,y)的路径上的点对答案不会产生任何影响,换句话说将lca(x,y)->...->x的路径直接压缩成lca(x,y)->x,对答案不会产生影响。因此我们只需要保留所有关键点,以及它们两两之间的lca,然后按照原数的祖先关系连边,在构造得到的虚树上面跑dp即可。注意到k个点两两之间不同的lca只有k-1个,因此产生的虚树是O(K)的。

下面来构造,首先按照在原树上的dfs将岛屿进行排序。

用一个栈维护从根节点到栈顶的路径上,需要加入虚树的点形成的一条链。注意不能直接将链中的点连边,因为有可能会有新的关键点的lca也在这条链上。考虑现在新加进来一个点x,以及栈顶的点p,t=lca(p,x),有以下几种情况。

1.t=p,那么把x加入栈就好了;

2.t!=p,那么显然t是p的祖先,那么显然栈中t->p的路径上面的点都可以加入虚树了,因为不可能会有新的lca插入到t->p的路径中来。

考虑2的具体实现,只要去除栈中的第二个元素,不断比较是否是t的祖先即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 250005
#define ll long long
#define inf 1e60
using namespace std;int n,m,tot,dfsclk,bin[25],pnt[N<<1],len[N<<1],nxt[N<<1],a[N],d[N],fa[N][18],pos[N],q[N];
ll val[N];
struct node{int fst[N];void add(int x,int y,int z){if (x==y) return;pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;}
}g1,g2;
int read(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }return x;
}
void dfs(int x){pos[x]=++dfsclk; int i,p;for (i=1; bin[i]<=d[x]; i++) fa[x][i]=fa[fa[x][i-1]][i-1];for (p=g1.fst[x]; p; p=nxt[p]){int y=pnt[p];if (y!=fa[x][0]){fa[y][0]=x; val[y]=min(val[x],(ll)len[p]);d[y]=d[x]+1; dfs(y);}}
}
int lca(int x,int y){if (d[x]<d[y]) swap(x,y); int tmp=d[x]-d[y],i;for (i=0; bin[i]<=tmp; i++)if (tmp&bin[i]) x=fa[x][i];for (i=17; i>=0; i--)if (fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; }return (x==y)?x:fa[x][0];
}
ll dp(int x){if (!g2.fst[x]) return val[x];int p; ll tmp=0;for (p=g2.fst[x]; p; p=nxt[p]) tmp+=dp(pnt[p]);g2.fst[x]=0; return min(tmp,val[x]);
}
bool cmp(int x,int y){ return pos[x]<pos[y]; }
void solve(){int i,cnt=read(),pts=1,tp=1; tot=0;for (i=1; i<=cnt; i++) a[i]=read();sort(a+1,a+cnt+1,cmp);for (i=2; i<=cnt; i++)if (lca(a[i],a[pts])!=a[pts]) a[++pts]=a[i];q[1]=1;for (i=1; i<=pts; i++){int tmp=lca(a[i],q[tp]);while (1){if (d[q[tp-1]]<=d[tmp]){g2.add(tmp,q[tp--],0);if (q[tp]!=tmp) q[++tp]=tmp; break;}g2.add(q[tp-1],q[tp],0); tp--;}if (q[tp]!=a[i]) q[++tp]=a[i];}while (tp>1){ g2.add(q[tp-1],q[tp],0); tp--; }printf("%lld\n",dp(1));
}
int main(){n=read(); int i;bin[0]=1; for (i=1; i<=18; i++) bin[i]=bin[i-1]<<1;for (i=1; i<n; i++){int x=read(),y=read(),z=read();g1.add(x,y,z); g1.add(y,x,z);}val[1]=inf; dfs(1);m=read(); while (m--) solve();return 0;
}

by lych

2016.3.6

bzoj2286 消耗战 虚树树形dp相关推荐

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

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

  2. P2495 [SDOI2011]消耗战-虚树+树形dp

    https://www.luogu.com.cn/problem/P2495 虚树:当我们在解决树形dp的问题的时候,题目中会给出一些询问,询问涉及的关键节点不多,并保证总的点数规模的时候,我们就可以 ...

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

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

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

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

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

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

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

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

  7. BZOJ 3611 [Heoi2014]:虚树+树形DP

    时空隧道 今天考试T3正解是虚树-..(看到这个名字我好虚啊-.) 现在我们需要处理一棵树上k个点的询问,做一遍树形DP-- 复杂度是O(n)的,q个询问,感觉复杂度很爆炸-..>_<-- ...

  8. BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

    题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. ...

  9. 「洛谷2495」「BZOJ3052」「SDOI2001」消耗战【虚树+树形动态规划】

    题目大意 给你\(k\)个点,让这一些点和一号节点断开,删去某一些边,求最小的删去边权之和. 做题的心路历程 做了\(HG\)昨天的模拟赛,深深感觉到了窝的菜,所以为了\(A\)掉T1这一道毒瘤,窝就 ...

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

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

最新文章

  1. 浏览器渲染引擎学习总结
  2. tf.where() 详解
  3. Ubuntu 14.04 安装SSH
  4. 从高频问题透视核心原理(转)
  5. 51单片机驱动8位数码管(74HC595驱动)滚动显示
  6. android实现带下划线的密码输入框
  7. PPT设计思维进阶:提升设计能力
  8. 产品经理必修课(4):深挖需求
  9. iOS之深入解析App Thinning的应用瘦身优化
  10. 【重构-改善代码】笔记
  11. 经Jerry为何会失去“编程的十年”(上)
  12. MAC M1/M2安装ADOBE等第三方软件问题终极解决 “开启任何来源”“无法检查更新,请确认您已接入互联网”“移除下载镜像的Quarantine属性” “闪退”【MACBOOK】
  13. redisclient工具个人理解
  14. windows验证和SQLSERVER验证有什么区别?--混合认证
  15. plc输出类型有哪些?
  16. 做seo软文编辑撰写经验
  17. IceSSL插件配置
  18. windows10家庭版个人电脑提升网速
  19. Excel如何实现单条件的一对多查找呢
  20. 太鸡冻了!用这种工艺画PCB,效率至少提升2倍,关键是还免费

热门文章

  1. 学云计算能干什么_电大是干什么的?属于什么教育?
  2. 关系数据库与对象数据库
  3. RT-THREAD + HC32F460 + AIR724 + ALIIOT
  4. 415 http请求 hutool_HTTP请求返回415错误码定位解决方法
  5. java水电费收费系统_基于SSM框架的JAVA水费电费管理系统
  6. 用android手机测量身高,教你如何使用小米手机测量自己的身高!
  7. 移动计算为王——我眼中的下一代计算机产业
  8. 计算机蓝屏一直重启,笔记本电脑开机蓝屏不断重启问题的解决方法
  9. 一种video视频兼容IE的模式
  10. php投影,投影效果怎么做?PS制作逼真的投影效果