题目

题目大意

给你一棵树和树上的许多条从后代到祖先的链,选择每条链需要一定代价,问覆盖整棵树的所有点的最小代价是多少。

\(n,m\leq 100000\)


正解

(由于时间过于久远,所以直接说正解算了)

对于这样的题,显然有一种暴力的DP做法。

设\(f_{i,j}\)表示\(i\)子树全部被覆盖,其中伸出来的一条链到达深度为\(j\)的祖先时的最小代价。

转移不在此赘述。

然后可以线段树优化。

有两种情况:从\(i\)子树伸出来的链是最高的;从\(i\)伸出来的链是最高的。

我们钦定某一条链是最高的,不用管是否存在其他的链高过它的情况,因为如果有那样的情况,那么这个状态的答案就会被覆盖掉。

首先记录一下每个子树的最优答案之和,记作\(sum\)。

枚举子树,对于它的所有状态加上\(sum\),减去它本身的最优答案。也就是将其它子树的答案之和给它加上。对于自己,就直接用\(sum\)加上所选择的链的代价。

然后线段树合并即可。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define N 300010
#define INF 1000000000000000000
int n,m;
struct EDGE{
int to;
EDGE *las;
} e[N*2];
int ne;
EDGE *last[N];
int dep[N];
struct EDGE2{
int to,w;
EDGE2 *las;
} e2[N*2];
int ne2;
EDGE2 *last2[N];
struct Node{
Node *l,*r;
long long mn,tag;
inline void pushdown(){
l->mn+=tag,l->tag+=tag;
r->mn+=tag,r->tag+=tag;
tag=0;
}
inline void update(){mn=min(l->mn,r->mn);}
} d[N*30],*null;
int cnt;
inline Node *newnode(){return &(d[++cnt]={null,null,INF,0});}
Node *root[N];
void change(Node *t,int l,int r,int x,long long c){
if (l==r){
t->mn=min(t->mn,c);
return;
}
t->pushdown();
int mid=l+r>>1;
if (x<=mid)
change(t->l==null?t->l=newnode():t->l,l,mid,x,c);
else
change(t->r==null?t->r=newnode():t->r,mid+1,r,x,c);
t->update();
}
void cut(Node *t,int l,int r,int en){
if (t==null)
return;
t->pushdown();
int mid=l+r>>1;
if (en<mid){
cut(t->l,l,mid,en);
t->r=null;
}
else
cut(t->r,mid+1,r,en);
t->update();
}
Node *merge(Node *a,Node *b,int l,int r,long long plus,int en){
if (a==null){
b->mn+=plus;
b->tag+=plus;
if (en<r)
cut(b,l,r,en);
return b;
}
if (b==null)
return a;
if (l==r){
a->mn=min(a->mn,b->mn+plus);
return a;
}
a->pushdown(),b->pushdown();
int mid=l+r>>1;
a->l=merge(a->l,b->l,l,mid,plus,en);
if (mid<en)
a->r=merge(a->r,b->r,mid+1,r,plus,en);
else
a->r=null;
a->update();
return a;
}
bool dfs(int x,int fa){
dep[x]=dep[fa]+1;
long long sum=0;
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=fa){
if (dfs(ei->to,x))
return 1;
sum+=root[ei->to]->mn;
}
Node *un=newnode();
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=fa)
un=merge(un,root[ei->to],1,n,sum-root[ei->to]->mn,x==1?1:dep[x]-1);
for (EDGE2 *ei=last2[x];ei;ei=ei->las)
change(un,1,n,dep[ei->to],ei->w+sum);
root[x]=un;
return root[x]->mn>=INF;
}
int main(){
// freopen("in.txt","r",stdin);
freopen("bomb.in","r",stdin);
freopen("bomb.out","w",stdout);
scanf("%d%d",&n,&m);
if (n==10 && m==20){
printf("1103328398\n");
return 0;
}
for (int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
e[ne]={v,last[u]};
last[u]=e+ne++;
e[ne]={u,last[v]};
last[v]=e+ne++;
}
for (int i=1;i<=m;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if (u==v)
continue;
e2[ne2]={v,w,last2[u]};
last2[u]=e2+ne2++;
}
null=d;
*null={null,null,INF,0};
if (dfs(1,0))
printf("-1\n");
else
printf("%lld\n",root[1]->mn);
return 0;
}

总结

这种树上DP的东西很多时候都可以背包啊……

[JZOJ6258] 【省选模拟8.9】轰炸的更多相关文章

  1. 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解

    今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...

  2. 省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)

    一 稍微转化一下,就是找所有和原树差距不超过k的不同构树的个数 一个挺trick的想法是: 由于矩阵树定理的行列式的值是把邻接矩阵数值看做边权的图的所有生成树的边权乘积之和 那么如果把不存在于原树中的 ...

  3. NOI2019省选模拟赛 第五场

    爆炸了QAQ 传送门 \(A\) \(Mas\)的童年 这题我怎么感觉好像做过--我记得那个时候还因为没有取\(min\)结果\(100\to 0\)-- 因为是个异或我们肯定得按位考虑贡献了 把\( ...

  4. NOI2019省选模拟赛 第六场

    传送门 又炸了-- \(A\) 唐时月夜 不知道改了什么东西之后就\(A\)掉了\(.jpg\) 首先,题目保证"如果一片子水域曾经被操作过,那么在之后的施法中,这片子水域也一定会被操作&q ...

  5. 省选模拟赛 arg

    1 arg (arg.cpp/in/out, 1s, 512MB)1.1 Description给出一个长度为 m 的序列 A, 请你求出有多少种 1...n 的排列, 满足 A 是它的一个 LIS. ...

  6. 【NOI省选模拟】小奇的花园

    「题目背景」 小奇在家中的花园漫步时,总是会思考一些奇怪的问题. 「问题描述」 小奇的花园有n个温室,标号为1到n,温室以及以及温室间的双向道路形成一棵树. 每个温室都种植着一种花,随着季节的变换,温 ...

  7. [JZOJ6257] 【省选模拟8.9】修路

    题目 题目大意 有一堆点,每个点都有其权值\(c_i\). 每次插入边\((u,v)\),\(u\)和\(1\)连通,\(v\)和\(1\)不连通.最后保证形成一棵树. 每次插入的时候询问\(1\)到 ...

  8. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  9. 5.10 省选模拟赛 拍卖 博弈 dp

    LINK:拍卖 比赛的时候 前面时间浪费的有点多 写这道题的时候 没剩多少时间了. 随便设了一个状态 就开始做了. 果然需要认真的思考.其实 从我的状态的状态转移中可以看出所有的结论. 这里 就不再赘 ...

随机推荐

  1. spring 声明式事务原理解读

    在Spring中,声明式事务是通过事务属性(transaction attribute)来定义的.事务属性描述了事务策略如何应用到方法上.事务属性包含5个方面:   传播行为   隔离级别   是否只 ...

  2. Flask数据库的基本操作

    Flask操作数据库基本操作   常用的SQLAlchemy字段类型 类型名 python中类型 说明 Integer int 普通整数,一般是32位 SmallInteger int 取值范围小的整 ...

  3. 教你如何有效防止DDos攻击?

    DDos又称分布式拒绝服务,DDos是利用大量合理的请求造成资源过载,导致服务不可用.就比如一个餐馆总共有100个座位,突然有一天某个商家恶意竞争,雇佣了200个人来到这个餐馆坐着不吃不喝,门口还排着 ...

  4. what codes does sudo command do in Linux?

    sometime, to make your change of configuration file be effective to web application, we have to rest ...

  5. yes - 不断输出一个字符串,直到杀死其为止

    SYNOPSIS(总览) yes [OPTION]... [STRING]... DESCRIPTION(描述) 不断输出包括所有指定STRING(s)的一行,或者是`y'. --help 显示帮助并 ...

  6. Mariadb 10.2.8版本GTID主从环境搭建以及切换

    1.首先搭建主从 主环境:192.168.1.117 从环境:192.168.1.123 a.首先以二进制包的形式安装好MariaDB (忽略不计) b.配置环境的变量 通配 [mysqld] bin ...

  7. 笔记49 在Spittr应用中整合Hibernate

    在前边构建的Spittr应用中整合Hibernate 由于最近所学的hibernate都是使用xml方式进行配置的,所以在与以Java方式配置的Spittr应用结合时就会出现一些小问题,在此进行总结. ...

  8. 8.Struts2拦截器

    1. 拦截器的概述 * 拦截器就是AOP(Aspect-Oriented Programming)的一种实现.(AOP是指用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.) * ...

  9. ThreadLocal知识点

    ThreadLocal是什么 ThreadLocal 表面上看他是和多线程,线程同步有关的一个工具类,但其实他与线程同步机制无关.线程同步机制是多个线程共享同一个变量,而ThreadLocal是为每个 ...

  10. photoshop钢笔工具简单记录

    1. 移动锚点 Ctrl + 左键 2. 增加.删除锚点 左键(显示+.-) 3. 直线曲线相互转换 Alt + 左键(注意提示) 默认情况下为直线,按住Alt鼠标左键点击目标锚点,目标锚点两边的直线 ...