BZOJ 2286 树链剖分+DFS序+虚树+树形DP
第一次学习虚树,就是把无关的点去掉。S里维护一条链即可。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
const LL Maxm=;
const LL Maxn=;
const LL Inf=1e60;
struct Node {LL to,next,w;}edge[Maxm],edge2[Maxm];
LL head[Maxn],head2[Maxn],dep[Maxn],H[Maxn],mark[Maxn],size[Maxn];
LL top[Maxn],father[Maxn],f[Maxn],S[Maxn],mn[Maxn];
LL cnt1,cnt2,tot,n,u,v,w,tp,m,K;
bool vis[Maxn];
inline void Add(LL u,LL v,LL w)
{edge[cnt1].to=v;edge[cnt1].next=head[u];edge[cnt1].w=w;head[u]=cnt1++;
edge[cnt1].to=u;edge[cnt1].next=head[v];edge[cnt1].w=w;head[v]=cnt1++;}
inline void Add2(LL u,LL v)
{if (u==v) return; edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++;}
inline LL Min(LL x,LL y) {return x>y?y:x;}
inline void Get_Int(LL &x)
{
x=; char ch=getchar(); LL f=;
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();} x*=f;
}
inline void Put_Int(LL x)
{
char ch[]; LL top=;
if (x==) ch[++top]='';
while (x) ch[++top]=x%+'',x/=;
while (top) putchar(ch[top--]); putchar('\n');
}
//================================================
void Dfs1(LL u)
{
mark[u]=++tot;vis[u]=true; size[u]=;
for (LL i=head[u];i!=-;i=edge[i].next)
if (!vis[edge[i].to])
{
dep[edge[i].to]=dep[u]+;
father[edge[i].to]=u;
mn[edge[i].to]=Min(mn[u],edge[i].w);
Dfs1(edge[i].to);
size[u]+=size[edge[i].to];
}
}
void Dfs2(LL u,LL chain)
{
top[u]=chain; vis[u]=true; LL k=;
for (int i=head[u];i!=-;i=edge[i].next)
if (!vis[edge[i].to] && (size[edge[i].to]>size[k] || k==)) k=edge[i].to;
if (k==) return;
Dfs2(k,chain);
for (int i=head[u];i!=-;i=edge[i].next)
if (!vis[edge[i].to] && i!=k) Dfs2(edge[i].to,edge[i].to);
}
inline LL Lca(LL u,LL v)
{
while (true)
{
if (top[u]==top[v]) return dep[u]>dep[v]?v:u;
if (dep[top[u]]>dep[top[v]]) u=father[top[u]];
else v=father[top[v]];
}
}
//=============================================================
inline bool cmp(LL x,LL y) {return mark[x]<mark[y];}
void Dp(LL u)
{ vis[u]=true; f[u]=mn[u]; LL ret=;
for (int i=head2[u];i!=-;i=edge2[i].next)
{
Dp(edge2[i].to);
ret+=f[edge2[i].to];
}
head2[u]=-;
if (ret) f[u]=Min(f[u],ret);
}
void Solve()
{
Get_Int(K);
for (int i=;i<=K;i++) Get_Int(H[i]);
sort(H+,H+K+,cmp);
tp=tot=; H[++tot]=H[];
for (int i=;i<=K;i++)
if (Lca(H[tot],H[i])!=H[tot]) H[++tot]=H[i];
cnt2=;
S[++tp]=;
for (int i=;i<=tot;i++)
{
LL u=H[i],f=Lca(u,S[tp]);
while (true)
{
if (dep[f]>=dep[S[tp-]])
{
Add2(f,S[tp--]);
if (S[tp]!=f) S[++tp]=f;
break;
}
Add2(S[tp-],S[tp]); tp--;
}
if (S[tp]!=u) S[++tp]=u;
}
while (--tp) Add2(S[tp],S[tp+]);
Dp();
Put_Int(f[]);
}
int main()
{
Get_Int(n);
memset(head,-,sizeof(head));cnt1=;
for (int i=;i<n;i++)
{
Get_Int(u),Get_Int(v),Get_Int(w);
Add(u,v,w),Add(v,u,w);
} father[]=; dep[]=; tot=; mn[]=Inf;
memset(vis,false,sizeof(vis));Dfs1();
memset(vis,false,sizeof(vis));Dfs2(,);
memset(head2,-,sizeof(head2));
Get_Int(m);
for (int i=;i<=m;i++) Solve();
return ;
}
C++
BZOJ 2286 树链剖分+DFS序+虚树+树形DP的更多相关文章
- BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】
一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...
- BZOJ - 4196 软件包管理器 (树链剖分+dfs序+线段树)
题目链接 设白色结点为未安装的软件,黑色结点为已安装的软件,则: 安装软件i:输出结点i到根的路径上的白色结点的数量,并把结点i到根的路径染成黑色.复杂度$O(nlog^2n)$ 卸载软件i:输出结点 ...
- [BZOJ - 2819] Nim 【树链剖分 / DFS序】
题目链接: BZOJ - 2819 题目分析 我们知道,单纯的 Nim 的必胜状态是,各堆石子的数量异或和不为 0 .那么这道题其实就是要求求出树上的两点之间的路径的异或和.要求支持单点修改. 方法一 ...
- BZOJ 3083: 遥远的国度(树链剖分+DFS序)
可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...
- 树链剖分&dfs序
树上问题 很多处理区间的问题(像是RMQ,区间修改).可以用线段树,树状数组,ST表这些数据结构来维护.但是如果将这些问题挪到了树上,就不能直接用这些数据结构来处理了.这时就用到了dfs序和树链剖分. ...
- 树链剖分||dfs序 各种题
1.[bzoj4034][HAOI2015]T2 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把 ...
- BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 1280 MBSubmit: 3127 Solved: 795[Submit][Status][Discu ...
- BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1352 Solved: 780[Submit][Stat ...
- BZOJ:2819 NIM(树链剖分||DFS序 &&NIM博弈)
著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取.谁不能取谁输.这个游戏是有必胜策略的.于是v ...
随机推荐
- ASP.NET Core + EF6
微软推出了全新的 .Net Core,于是我就想着在目前接手的项目中使用这项新技术.但是因为预算的原因,我们所用的数据库是 MySql .但是最新的 EF Core 并不支持 MySql ,所以目前我 ...
- QA、Selenium WebDriver (Q&A)
Q:启动IE浏览器时突然报下面错误,不能正常使用. WebDriverException: Message: Unexpected error launching Internet Explo ...
- Duilib实现QQ聊天窗口晃动
转载:http://blog.csdn.net/arbboter/article/details/26282717 转载:http://blog.csdn.net/zerolusta/article/ ...
- Cheatsheet: 2016 02.01 ~ 02.29
Web How to do distributed locking Writing Next Generation Reusable JavaScript Modules in ECMAScript ...
- 手机号码归属地查询api接口
淘宝网 API地址: http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=15850781443 参数: tel:手机号码 返回:JSON ...
- VirtualProvider (VirtualCube)虚拟立方体
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- linux 知识汇总
1 ) linux下文件系统类型的学习 2 )深入理解linux i节点(inode) 3 )RAID系列
- Android Gradle 完整指南
为什么需要学Gradle? Gradle 是 Android 现在主流的编译工具,虽然在Gradle 出现之前和之后都有对应更快的编译工具出现,但是 Gradle 的优势就在于它是亲儿子,Gradle ...
- STM32学习笔记(十) CAN通讯测试(环回模式)
1.CAN通讯的理解 想学习CAN通讯,那么要对通讯协议有一定的认知.通讯协议是指通信双方对数据传送控制的一种约定.约定中包括对数据格式,同步方式,传输速度,传送步骤,检纠错方式以及控制字符定义等问题 ...
- 被table单元格colspan属性折磨了
基础知识不牢固,被colspan折磨了很长时间 table里面的td使用colspan前提条件是所跨的单元格宽度必须一样,不然显示效果会是属性不起作用或直接导致表格变形,下面的例子可以看出效果 < ...