Luogu P2495 [SDOI2011]消耗战

problem

Solution

苦思冥想稍作思考之后可以得到一个树形DP的方法:
令\(w(u,v)\)表示u,v之间的边的权值,\(f[u]\)表示以\(u\)为根的子树(不含\(u\))中所有关键点与根断开的最小代价,则转移方程为:
\[f[u]=\begin{cases}w(u,v)&\text{如果v是关键点}\\min(w(u,v),dp[v])&\text{如果v非关键点}\end{cases}\]

复杂度为\(O(nm)\),显然不正确

对于每次询问可以建立一颗虚树,边权为关键点之间最小的权值

在这道题中,如果一个关键点\(u\)的祖先中有关键点\(v\),那么\(u\)是不需要加入虚树的,因为\(v\)一定需要断开,同时也就断开了\(u\)

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define maxn 250005
using namespace std;
typedef long long ll;const ll inf=0x7f7f7f7f7f7f7f7f;
int n,m,k,h[maxn];
int dep[maxn],dfn[maxn],sign,prt[maxn][21],key[maxn];
ll dp[maxn],mnc[maxn][21];struct edge
{int u,v,nxt;ll w;
};namespace Ori
{edge g[maxn*2];int head[maxn],ecnt;void eADD(int u,int v,ll w){g[++ecnt].u=u;g[ecnt].v=v;g[ecnt].w=w;g[ecnt].nxt=head[u];head[u]=ecnt;}
}namespace New
{edge g[maxn];int head[maxn],ecnt;void eADD(int u,int v,ll w){g[++ecnt].u=u;g[ecnt].v=v;g[ecnt].w=w;g[ecnt].nxt=head[u];head[u]=ecnt;}void Inti(){for(register int i=1;i<=ecnt;++i)g[i].u=g[i].v=g[i].nxt=0,g[i].w=0LL;ecnt=0;}
}void dfs(int u,int fa,int depth,ll w)
{dep[u]=depth,prt[u][0]=fa,mnc[u][0]=w,dfn[u]=++sign;for(register int i=1;(1<<i)<=depth;++i){prt[u][i]=prt[prt[u][i-1]][i-1];mnc[u][i]=min(mnc[u][i-1],mnc[prt[u][i-1]][i-1]);}for(register int i=Ori::head[u];i;i=Ori::g[i].nxt){int v=Ori::g[i].v;if(v==fa)continue;dfs(v,u,depth+1,Ori::g[i].w);}
}int LCA(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(register int i=20;i>=0;--i)if(dep[prt[x][i]]>=dep[y])x=prt[x][i];if(x==y)return x;for(register int i=20;i>=0;--i)if(prt[x][i]!=prt[y][i])x=prt[x][i],y=prt[y][i];return prt[x][0];
}bool cmp(const int &a,const int &b)
{return dfn[a]<dfn[b];
}ll getmnc(int u,int v)
{ll re=inf;if(dep[u]<dep[v])swap(u,v);for(register int i=20;i>=0;--i)if(dep[prt[u][i]]>=dep[v])re=min(re,mnc[u][i]),u=prt[u][i];return re;
}int top,stk[maxn];
void Build()
{for(register int i=1;i<=k;++i){if(top==1){stk[++top]=h[i];continue;}int lca=LCA(stk[top],h[i]);if(lca==stk[top])continue;while(top>1 && dfn[stk[top-1]]>=dfn[lca])New::eADD(stk[top-1],stk[top],getmnc(stk[top-1],stk[top])),--top;if(lca!=stk[top])New::eADD(lca,stk[top],getmnc(lca,stk[top])),stk[top]=lca;stk[++top]=h[i];}while(top-1)New::eADD(stk[top-1],stk[top],getmnc(stk[top],stk[top-1])),--top;
}void DP(int u)
{dp[u]=0;if(!New::head[u])return;for(register int i=New::head[u];i;i=New::g[i].nxt){int v=New::g[i].v;DP(v);if(key[v])dp[u]+=New::g[i].w;elsedp[u]+=min(New::g[i].w,dp[v]);}New::head[u]=0;
}int main()
{scanf("%d",&n);for(register int i=1;i<n;++i){int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);Ori::eADD(u,v,w),Ori::eADD(v,u,w);}dfs(1,0,1,inf);scanf("%d",&m);while(m--){scanf("%d",&k);for(register int i=1;i<=k;++i){scanf("%d",&h[i]);key[h[i]]=1;}sort(h+1,h+k+1,cmp);top=0;stk[++top]=1;New::Inti();Build();DP(1);printf("%lld\n",dp[1]);for(register int i=1;i<=k;++i)key[h[i]]=0;}return 0;
}

转载于:https://www.cnblogs.com/lizbaka/p/10289894.html

「Luogu2495」 [SDOI2011]消耗战 虚树相关推荐

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

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

  2. 洛谷 P2495 [SDOI2011]消耗战 虚树

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

  3. P2495 [SDOI2011]消耗战 虚树入门

    一棵树,n个点m个操作.每条边有权值,每个操作给你k个点,问断开若干条边后使k个点与根不相连的最小边权和是多少. 有sigmaK<500000 易知一个裸的树dp需要复杂度,m次操作后总复杂度为 ...

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

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

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

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

  6. LibreOJ 6514. 「雅礼集训 2018 Day10」文明【虚树+LCA】

    6514. 「雅礼集训 2018 Day10」文明 [题目描述] 传送门 [题解] 考虑笨蛋的写法,可以用LCA求出1号和其他点的中点,然后DFS搜索Size大小即可,但是,复杂度显然要炸,但是我们会 ...

  7. c++虚函数_「C++」对象模型和虚函数

    普通成员函数跟着类 ,虚函数跟着对象 ①作为普通成员函数 class A{public:void print(){cout << " class A " << ...

  8. LG5200 「USACO2019JAN」Sleepy Cow Sorting 树状数组

    \(\mathrm{Sleepy Cow Sorting}\) 问题描述 LG5200 题解 树状数组. 设\(c[i]\)代表\([1,i]\)中归位数. 显然最终的目的是将整个序列排序为一个上升序 ...

  9. LOJ#3159. 「NOI2019」弹跳(四分树+dijkstra)

    传送门 n2n^2n2暴力显然,考虑优化. 有一种想法是使用四分树/kd-tree/树套树,发现你并不能得到100pts100pts100pts的好成绩(空间会炸掉) 考试的时候比较智熄,先暴力四分树 ...

最新文章

  1. logistic回归 如何_第七章:利用Python实现Logistic回归分类模型
  2. jupyter安装与初探
  3. CentOS7 NTP客户端和服务器安装和使用
  4. 电话双音频拨码信号采集
  5. 1000 qps java,什么是QPS?
  6. 【小练习05】HTML+CSS--淘宝商铺小页面
  7. app分发平台java_集成 Asset Delivery (Java)
  8. 都江堰很美-佩服古人_Crmhf的一天
  9. linux的HAL库函数,STM32 HAL库 IIC 协议库函数
  10. ajax请求中带判断语句例子,jQuery中借助deferred来请求及判断AJAX加载的实例讲解...
  11. P2S、P2P、P2SP之对比
  12. HDOJ 4944 FSF’s game
  13. hashcat简单使用
  14. 2017年10月30日360最新虚拟壳脱壳后完全修复
  15. python利用公式计算_Python利用openpyxl处理Excel文件(公式实例)
  16. CN基于词库的中文转拼音优质解决方案,单类单文件版,支持低版本PHP
  17. react-dnd官方文档
  18. mini2440 的 leds的驱动程序
  19. 机器学习中的数学——随机变量
  20. perror()函数

热门文章

  1. 为什么“时间管理四象限”没有用处?
  2. 【数据分析】了解数据分析
  3. 【Leetcode刷题】:Python:494. 目标和
  4. 第十四届蓝桥杯. 接龙数列(线性DP)
  5. React Native腾讯广告优量汇广点通广告SDK集成
  6. 什么是数字化供应链系统?企业如何利用数字化供应链系统增加销售渠道?
  7. jackson序列化错误 get类型方法名的坑 [com.fasterxml.jackson.databind.exc.InvalidDefinitionException]
  8. 国家电网利润超五大发电集团净利总和
  9. 路由器的千兆是什么意思_千兆赫兹ghz到底是什么意思
  10. 孙宇晨被调查背后:网民狂欢不能代替常识