思路

虚树上DP

虚树相当于一颗包含了所有询问的关键点信息的树,包含的所有点只有询问点和它们的LCA,所以点数是\(2k\)级别的,这样的话复杂度就是\(O(\sum k)\),复杂度就对了

虚树重点就是虚树的构造

用栈可以进行虚树的构造

过程如下

设现在加入点u

如果栈为空或只有一个元素,直接加入即可(延长当前链)

如果LCA(u,S[top])=S[top],把u加入即可(延长树链)

否则证明u和S中的树链在lca的两个子树中,在dfn[lca]<=dfn[S[top-1]]的条件下,从S[top-1]向S[top]连边,然后弹出

如果最后lca=S[top],证明这颗子树构造完成,加入u即可

否则证明lca在S[top-1]和S[top]之间,从lca向S[top]连边,然后pop出S[top],lca入栈

最后把u加入即可

这题建出虚树之后就直接DP就好了

如果u不是关键点

\(DP[u]=\sum_{v\in son[u]} min(minx[v],DP[v])\)

如果u是关键点

\(DP[u]=minx[u]\)

minx[u]是断开1到u路径的最小代价

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <vector>
#define int long long
using namespace std;
const int MAXN = 250010;
int n,m;
struct Graph{
vector<int> to[MAXN],wx[MAXN];
void addedge(int ui,int vi,int wi){
to[ui].push_back(vi);
wx[ui].push_back(wi);
}
}G1,G2;
int S[MAXN],topx,dfn[MAXN],dfs_clock,fa[MAXN][20],dep[MAXN],minx[MAXN],mark[MAXN];
void dfs1(int u,int f){
dep[u]=dep[f]+1;
dfn[u]=++dfs_clock;
fa[u][0]=f;
for(int i=1;i<20;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=0;i<G1.to[u].size();i++){
int vi=G1.to[u][i];
if(vi==f)
continue;
minx[vi]=min(G1.wx[u][i],minx[u]);
dfs1(vi,u);
}
}
int lca(int x,int y){
if(dep[x]<dep[y])
swap(x,y);
for(int i=19;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y)
return x;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
bool cmp(int a,int b){
return dfn[a]<dfn[b];
}
void insert(int u){
if(topx<=1){
S[++topx]=u;
return;
}
int Lca=lca(u,S[topx]);
if(Lca==S[topx]){
S[++topx]=u;
return;
}
while(topx>1&&dfn[Lca]<=dfn[S[topx-1]]){
G2.addedge(S[topx-1],S[topx],0);
topx--;
}
if(Lca!=S[topx]){
G2.addedge(Lca,S[topx],0);
S[topx]=Lca;
}
S[++topx]=u;
}
int dfs2(int u){
int ans=0;
for(int i=0;i<G2.to[u].size();i++)
ans+=min(minx[G2.to[u][i]],dfs2(G2.to[u][i]));
G2.to[u].clear();
if(mark[u]){
mark[u]=false;
return minx[u];
}
else
return ans;
}
vector<int> im;
signed main(){
scanf("%lld",&n);
for(int i=1;i<n;i++){
int a,b,c;
scanf("%lld %lld %lld",&a,&b,&c);
G1.addedge(a,b,c);
G1.addedge(b,a,c);
}
minx[1]=0x3f3f3f3f;
dfs1(1,0);
scanf("%lld",&m);
for(int i=1;i<=m;i++){
im.clear();
int x,k;
scanf("%lld",&k);
for(int j=1;j<=k;j++){
scanf("%lld",&x);
im.push_back(x);
mark[x]=true;
}
sort(im.begin(),im.end(),cmp);
insert(1);
for(int i=0;i<im.size();i++)
insert(im[i]);
while(topx>0){
G2.addedge(S[topx-1],S[topx],0);
topx--;
}
printf("%lld\n",dfs2(1));
}
return 0;
}

P2495 [SDOI2011]消耗战的更多相关文章

  1. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

  2. ●洛谷P2495 [SDOI2011]消耗战

    题链: https://www.luogu.org/problemnew/show/P2495题解: 虚树入门,树形dp 推荐博客:http://blog.csdn.net/lych_cys/arti ...

  3. P2495 [SDOI2011]消耗战 lca倍增+虚树+树形dp

    题目:给出n个点的树  q次询问  问切断 k个点(不和1号点联通)的最小代价是多少 思路:树形dp  sum[i]表示切断i的子树中需要切断的点的最小代价是多少 mi[i]表示1--i中的最小边权 ...

  4. 洛谷P2495 [SDOI2011]消耗战(虚树)

    题面 传送门 题解 为啥一直莫名其妙\(90\)分啊--重构了一下代码才\(A\)掉-- 先考虑直接\(dp\)怎么做 树形\(dp\)的时候,记一下断开某个节点的最小值,就是从根节点到它的路径上最短 ...

  5. [洛谷P2495][SDOI2011]消耗战

    题目大意:有一棵$n(n\leqslant2.5\times10^5)$个节点的带边权的树,$m$个询问,每次询问给出$k(\sum\limits_{i=1}^mk_i\leqslant5\times ...

  6. 洛谷 P2495 [SDOI2011]消耗战(虚树,dp)

    题面 洛谷 题解 虚树+dp 关于虚树 了解一下 具体实现 inline void insert(int x) { if (top == 1) {s[++top] = x; return ;} int ...

  7. P2495 [SDOI2011]消耗战 虚树

    这是我做的第一道虚树题啊,赶脚不错.其实虚树也没什么奇怪的,就是每棵树给你一些点,让你多次查询,但是我不想每次都O(n),所以我们每次针对给的点建一棵虚树,只包含这些点和lca,然后在这棵虚树上进行树 ...

  8. luogu P2495 [SDOI2011]消耗战 |虚树+LCA+dp

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

  9. Luogu P2495 [SDOI2011]消耗战

    题目 我们可以很快的想到一个单次\(O(n)\)的dp. 然后我们注意到这个dp有很多无用的操作,比如一条没有关键点的链可以直接去掉. 所以我们可以尝试一次dp中只管那些有用的点. 题目给的关键点显然 ...

随机推荐

  1. kafka手动开启监听

    项目集成spring-kafka,在项目启动后需要做些初始化资源的任务,kafka消费会依赖这些所以需要配置kafka手动启动. 类似这样,设置autoStartup为false 然后代码里面调用这个 ...

  2. Mac OSX bash function 备份

    # mount the android file image function mountAndroid { hdiutil attach ~/android.dmg.sparsefile.spars ...

  3. 【托业】【怪兽】TEST03

    101. engage  [ɪnˈgeɪdʒ]  v.参与 102. toner [ˈtəʊnə(r)]n.碳粉匣 103. surveillance [sɜ:ˈveɪləns]n.监控 105. i ...

  4. 跨主机网络overlay和macvlan模型

    overlay网络模型 无论是openstack还是docker都是先创建一个网络然后再创建虚机或者容器  并把创建的虚机或者容器运行在此网络中 Docker 提供了 overlay driver,使 ...

  5. Linux系统(四)LVS集群负载均衡NAT模式

    序言 提到LVS,就从章文嵩博士开始吧,反正也不知道如何下笔来写这一篇.章大博士,读博时候创建这个lvs软件项目,但是他提倡开源精神,在用户的建议和反馈中,这个花了他两周时间开发的开源软件不断得到改建 ...

  6. abap test seam 和 TEST-INJECTION

    TEST-SEAM 和 TEST-INJECTION 一块儿使用 可以模拟出调用方法的return,exporting,chaning值.  例如: 1: 假设有一个类zcl_demo_input,该 ...

  7. 3.2.2 SpringMVC配置式开发

    SpringMVC配置式开发 1. SpringMVC运行原理(执行过程) 2. 需求 用户提交一个请求, 服务端处理器接收到请求后, 给出一条信息,在相应页面中显示该条信息 3. 开发步骤 (1) ...

  8. 谷歌AM HTML视频代码amp-video示例

    ntroduction Use amp-video to embed videos into your AMP HTML files. Video source files must be serve ...

  9. Visual Studio 独立 Shell 下载

    https://visualstudio.microsoft.com/zh-hans/vs/older-downloads/isolated-shell/ SSMS 2017 安装问题 https:/ ...

  10. C++ 用三元组表示法存储稀疏矩阵

    若有一个矩阵(m*n),其中非0元素个数远少于数值为0的元素个数,若开辟一个m*n大空间,来存储这样一个很多元素值为0的矩阵,浪费空间,于是我们只存储这些非0的元素的下标及数值 用一个结构体——三元组 ...