Codeforces 671D. Roads in Yusland(树形DP+线段树)
调了半天居然还能是线段树写错了,药丸
这题大概是类似一个树形DP的东西。设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路。如果我们枚举每条路去转移,会发现这条路沿线上的其他子树的答案难以统计,那怎么办呢,我们可以让这条路向上回溯的时候顺便记录一下,于是有$val[i]$表示必修i这条路,并且修完当前子树的最小代价。
则有转移$dp[x]=min(val[j])$,且$j$这条路必须覆盖$x$。
$val[i]=(\sum dp[son])-dp[sonx]+val[i]$,且$i$这条路必须覆盖$sonx$。
转移用线段树来维护就好,至于怎么判断某条路是否覆盖两个点,只要递归到某条路的起点的时候把$val[i]$改为$(\sum dp[son])+cost[i]$,递归到某条路终点的时候把$val[i]$改为$inf$就好了。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
const ll inf=1e15;
struct poi{ll sum, delta;}tree[maxn<<];
struct tjm{int too, pre;}e[maxn<<], e2[maxn<<], e3[maxn<<];
struct qaq{int x, y, cost, pos;}q[maxn];
ll dp[maxn];
int n, m, x, y, tot, tot2, tot3, tott, l[maxn], r[maxn], last[maxn], last2[maxn], last3[maxn];
inline void read(int &k)
{
int f=; k=; char c=getchar();
while(c<'' || c>'') c=='-' && (f=-), c=getchar();
while(c<='' && c>='') k=k*+c-'', c=getchar();
k*=f;
}
inline void add(int x, int y){e[++tot]=(tjm){y, last[x]}; last[x]=tot;}
inline void add2(int x, int y){e2[++tot2]=(tjm){y, last2[x]}; last2[x]=tot2;}
inline void add3(int x, int y){e3[++tot3]=(tjm){y, last3[x]}; last3[x]=tot3;}
inline void up(int x) {tree[x].sum=min(tree[x<<].sum, tree[x<<|].sum);}
inline void addone(int x, int l, int r, ll delta)
{
tree[x].delta=min(inf, tree[x].delta+delta);
tree[x].sum=min(inf, tree[x].sum+delta);
}
inline void down(int x, int l, int r)
{
int mid=(l+r)>>;
addone(x<<, l, mid, tree[x].delta);
addone(x<<|, mid+, r, tree[x].delta);
tree[x].delta=;
}
void build(int x, int l, int r)
{
if(l==r) {tree[x].sum=inf; return;}
int mid=(l+r)>>;
build(x<<, l, mid); build(x<<|, mid+, r);
up(x);
}
void update(int x, int l, int r, int cx, ll delta)
{
if(l==r) {tree[x].sum=delta; return;}
down(x, l, r);
int mid=(l+r)>>;
if(cx<=mid) update(x<<, l, mid, cx, delta);
else update(x<<|, mid+, r, cx, delta);
up(x);
}
void change(int x, int l, int r, int cl, int cr, ll delta)
{
if(cl>cr) return;
if(cl<=l && r<=cr) {addone(x, l, r, delta); return;}
down(x, l, r);
int mid=(l+r)>>;
if(cl<=mid) change(x<<, l, mid, cl, cr, delta);
if(cr>mid) change(x<<|, mid+, r, cl, cr, delta);
up(x);
}
ll query(int x, int l, int r, int cl, int cr)
{
if(cl>cr) return inf;
if(cl<=l && r<=cr) return tree[x].sum;
down(x, l, r);
int mid=(l+r)>>; ll ans=inf;
if(cl<=mid) ans=query(x<<, l, mid, cl, cr);
if(cr>mid) ans=min(ans, query(x<<|, mid+, r, cl, cr));
return ans;
}
void dfs1(int x, int fa)
{
l[x]=++tott;
for(int i=last[x], too;i;i=e[i].pre)
if((too=e[i].too)!=fa) dfs1(too, x);
r[x]=tott;
}
inline int find(int x)
{
int l=, r=m+;
while(l<r)
{
int mid=(l+r)>>;
if(q[mid].pos>=x) r=mid;
else l=mid+;
}
return l;
}
void dfs2(int x, int fa)
{
ll sum=;
for(int i=last[x], too;i;i=e[i].pre)
if((too=e[i].too)!=fa) dfs2(too, x), sum=min(inf, sum+dp[too]);
if(x==) {dp[]=sum; return;}
for(int i=last2[x];i;i=e2[i].pre) update(, , m, e2[i].too, min(inf, q[e2[i].too].cost+sum));
for(int i=last3[x];i;i=e3[i].pre) update(, , m, e3[i].too, inf);
for(int i=last[x], too;i;i=e[i].pre)
if((too=e[i].too)!=fa) change(, , m, find(l[too]), find(r[too]+)-, sum-dp[too]);
dp[x]=query(, , m, find(l[x]), find(r[x]+)-);
}
inline bool cmp(qaq a, qaq b){return a.pos<b.pos;}
int main()
{
read(n); read(m); build(, , m);
for(int i=;i<n;i++) read(x), read(y), add(x, y), add(y, x);
dfs1(, );
for(int i=;i<=m;i++) read(q[i].x), read(q[i].y), read(q[i].cost), q[i].pos=l[q[i].x];
sort(q+, q++m, cmp); q[m+].pos=n+;
for(int i=;i<=m;i++) add2(q[i].x, i), add3(q[i].y, i);
dfs2(, );
if(dp[]>=inf) return puts("-1"), ;
printf("%lld\n", dp[]);
}
Codeforces 671D. Roads in Yusland(树形DP+线段树)的更多相关文章
- Codeforces 671D Roads in Yusland [树形DP,线段树合并]
洛谷 Codeforces 这是一个非正解,被正解暴踩,但它还是过了. 思路 首先很容易想到DP. 设\(dp_{x,i}\)表示\(x\)子树全部被覆盖,而且向上恰好延伸到\(dep=i\)的位置, ...
- Codeforces Round #530 (Div. 2) F (树形dp+线段树)
F. Cookies 链接:http://codeforces.com/contest/1099/problem/F 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干 ...
- codeforces 671D Roads in Yusland & hdu 5293 Tree chain problem
dp dp优化 dfs序 线段树 算是一个套路.可以处理在树上取链的问题.
- POJ 3162 Walking Race 树形DP+线段树
给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...
- Codeforces 629D Babaei and Birthday Cakes DP+线段树
题目:http://codeforces.com/contest/629/problem/D 题意:有n个蛋糕要叠起来,能叠起来的条件是蛋糕的下标比前面的大并且体积也比前面的大,问能叠成的最大体积 思 ...
- hdu5293 Tree chain problem 树形dp+线段树
题目:pid=5293">http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最 ...
- poj3162(树形dp+线段树求最大最小值)
题目链接:https://vjudge.net/problem/POJ-3162 题意:给一棵树,求每个结点的树上最远距离,记为a[i],然后求最大区间[l,r]满足区间内的max(a[i])-min ...
- 【洛谷5298】[PKUWC2018] Minimax(树形DP+线段树合并)
点此看题面 大致题意: 有一棵树,给出每个叶节点的点权(互不相同),非叶节点\(x\)至多有两个子节点,且其点权有\(p_x\)的概率是子节点点权较大值,有\(1-p_x\)的概率是子节点点权较小值. ...
- Codeforces Round #530 (Div. 2)F Cookies (树形dp+线段树)
题:https://codeforces.com/contest/1099/problem/F 题意:给定一个树,每个节点有俩个信息x和t,分别表示这个节点上的饼干个数和先手吃掉这个节点上一个饼干的的 ...
随机推荐
- Sublime Text3添加右键
在Sublime Text3安装目录下新建一个文件 sublime_addright.inf 文件内容: [Version] Signature="$Windows NT$" [D ...
- katalon系列八:Katalon Studio图片识别
Katalon Studio自带集成了图片识别功能,有2个比较有用的图片识别相关的命令:Wait For Image Present和Click Image.这里重点讲下Click Image命令: ...
- Unity中几个特殊路径在各个平台的访问方式
1.文件路径Resources:Unity在发布成移动端项目后,其他文件路径都将不存在,但是如果有一些必要的资源,可以放在Resources文件夹下,因为这个文件夹下的所有资源是由Unity内部进行调 ...
- 用Python实现检测视频真伪?
译者注:本文以一段自打24小时耳光的视频为例子,介绍了如何利用均值哈希算法来检查重复视频帧.以下是译文. 有人在网上上传了一段视频,他打了自己24个小时的耳光.他真的这么做了吗?看都不用看,肯定没有! ...
- python编辑购物车
一.需求分析 输入工资金额,进入购物车,并打印输出商品编号和价格,用户可以通过输入商品编号进行商品选购 余额不足时,打印提示信息 通过q进行退出结算 购物车能够循环购物 二.代码实现 ShoopCar ...
- 《数据结构与算法JavaScript描述》中的一处错误
最近在看<数据结构与算法JavaScript描述>这本书,看到选择排序这部分时,发现一个比较大的错误. 原书的选择排序算法是这样的: function selectionSort() { ...
- php作用域限定符
双冒号::被认为是作用域限定操作符,用来指定类中不同的作用域级别.::左边表示的是作用域,右边表示的是访问的成员. 系统定义了两个作用域,self和parent.self表示当前类的作用域,在类之外的 ...
- 软工网络15团队作业4-DAY2
每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 张陈东芳:查看数据库的连接 吴敏烽:规范商品实体类 周汉麟:研究获取商品信息的方法 林振斌:研究获取商 ...
- JS高级 2
递归:函数自己调用自己 在JavaScript中唯一能产生作用域的东西是 函数!js中只有函数可以创建作用域 词法作用域,也叫做静态作用域 //就是在代码写好的那一刻,变量和函数的作用域就已经确定了, ...
- perf的采样模式和统计模式
perf的采样模式和统计模式 统计模式和采样模式使用寄存器的方法不相同; 在统计模式下,每次调度之前设置寄存器,调度之后清理寄存器,留个下个进程使用;PMU寄存器的使用方法; 在采样模式下,每次 pm ...