题目大意

​ 给定一颗 \(N\) 个点的有根树,其中 \(1\) 是树根,除了 \(1\) 以外的其他点 \(u\) 有唯一的父亲 \(Father_u\)。同时,给定 \(M\) 条路径,第 \(i\) 条路径是 \((s_i,t_i)\),保证 \(s_i\) 是 \(t_i\) 的祖先。你可以任意选择若干条路径。如果第 \(i\) 条路径被选择,那么你可以得到 \(V_i\) 的收益,这里保证 \(V_i\) 是非负的。

​ 同时,对于每个不是 \(1\) 的点 \(u\),考虑其连接它的父亲 \(Father_u\) 的边,如果有 \(x\) 条覆盖了它且被选择的路径,需要花费代价 \(A_u\times x^2+B_u\times x\),这里也保证 \(A_u\) 和 \(B_u\) 是非负的。代价的含义就是收益要减去这么多,相当于负的收益。

​ 你需要求出在以上条件下你的最大收益。

数据范围:\(1\leq N,M\leq 150\),\(\forall2\leq u\leq N,0\leq A_u \leq 100,0\leq B_u \leq 10000\),\(\forall 1\leq i \leq M,0\leq V_i \leq 10^6\),并保证 \(s_i\) 总是 \(t_i\) 的祖先。

时间限制:1000ms

空间限制:1024MB

解题思路

题解直接给出了费用流的建图方案,然后证明正确性,这里还是想想要如何想到使用费用流。

数据范围只是一个小点,不过确实可以考虑按照数据范围整理一个常用算法表。

关键点应该在于费用是二次的,像这种似乎是很不好处理的,如果是全局二次的话,大概还可以二分或者枚举一下次数,但是这是每条边都是一个二次费用,所以目前所知道的算法里,只有费用流按每次连边能实现这一点,因为对于费用的贪心可以保证按照需要的顺序流过这些流。

于是就考虑建图。费用流有一种常见的做法是先考虑全部都选择,然后计算需要减去的费用, 那么要么是减去 \(v_i\) 直接不选,要么是减去路上的费用,按照这个思路建图就好了。

#include <bits/stdc++.h>
using namespace std; const int N(155), E(N * (N + 3)), INF(1e9); int n, m, fa[N], a[N], b[N], s[N], t[N], v[N];
int ans;
int cnt = 1, head[N];
int S, T, dcnt, dis[N], flo[N], pre[N], inq[N];
struct edge{ int nx, to, v, f; } e[E << 1]; inline void read(int &x){
x = 0; int f = 1, c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) x = x * 10 + c - 48, c = getchar();
x *= f;
} inline void input(){
read(n), read(m);
for(int i(2); i <= n; ++i) read(fa[i]), read(a[i]), read(b[i]);
for(int i(1); i <= m; ++i) read(s[i]), read(t[i]), read(v[i]);
} inline void add(int u, int v, int w, int f){
e[++cnt] = {head[u], v, w, f}, head[u] = cnt;
e[++cnt] = {head[v], u, -w, 0}, head[v] = cnt;
}
inline void prep(){
S = n + 1, T = 1, dcnt = n + 1;
for(int i(2); i <= n; ++i)
for(int j(1); j <= m; ++j) add(i, fa[i], (j * 2 - 1) * a[i] + b[i], 1);
for(int i(1); i <= m; ++i)
add(S, t[i], 0, 1), add(s[i], T, 0, 1), add(t[i], s[i], v[i], 1), ans += v[i];
} bool spfa(){
static queue <int> Q;
for(int i(1); i <= dcnt; ++i) dis[i] = INF;
dis[S] = 0, flo[S] = INF, Q.push(S), inq[S] = 1;
while(!Q.empty()){
int x = Q.front(); Q.pop(), inq[x] = 0;
for(int i(head[x]); i; i = e[i].nx){
int y = e[i].to;
if(dis[y] > dis[x] + e[i].v && e[i].f){
dis[y] = dis[x] + e[i].v;
flo[y] = min(flo[x], e[i].f);
pre[y] = i;
if(!inq[y]) Q.push(y), inq[y] = 1;
}
}
}
return dis[T] != INF;
}
inline void work(){
int mf = 0, mc = 0;
while(spfa()){
mf += flo[T], mc += flo[T] * dis[T];
int now = T;
while(now){
now = pre[now];
e[now].f -= flo[T], e[now ^ 1].f += flo[T];
now = e[now ^ 1].to;
}
}
ans -= mc;
} inline void output(){ printf("%d\n", ans); } int main(){
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
input();
prep();
work();
output();
return 0;
}

[题解] 树(tree)的更多相关文章

  1. 树(tree)

    树(tree)[题目描述]从前在森林里面有一棵很大的树,树上住着很多小动物.树上有

  2. JS--插件: 树Tree 开发与实现

    日常在Web项目开发时,经常会碰到树形架构数据的显示,从数据库中获取数据,并且显示成树形.为了方便,我们可以写一个javascript的一个跨浏览器树控件,后续可以重复使用.本节分享一个自己开发的JS ...

  3. POJ1741:Tree——题解+树分治简要讲解

    http://poj.org/problem?id=1741 题目大意:给一棵树,求点对间距离<=k的个数. ———————————————————— 以这道题为例记录一下对于树分治的理解. 树 ...

  4. [LeetCode 题解]: Symmetric Tree

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述   Given a ...

  5. 竞赛题解 - Broken Tree(CF-758E)

    Broken Tree(CF-758E) - 竞赛题解 贪心复习~(好像暴露了什么算法--) 标签:贪心 / DFS / Codeforces 『题意』 给出一棵以1为根的树,每条边有两个值:p-强度 ...

  6. 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)

    题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...

  7. leetcode题解:Binary Tree Postorder Traversal (二叉树的后序遍历)

    题目: Given a binary tree, return the postorder traversal of its nodes' values. For example:Given bina ...

  8. leetcode 题解:Binary Tree Preorder Traversal (二叉树的先序遍历)

    题目: Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binar ...

  9. 轻量级jquery框架之--树(tree)

    前言 在常用的UI组件中,树形组件与数据列表组件可以说是构成一个管理平台基本的两大数据核心组件.树形组件用于系统菜单,数据列表用于数据表现,两者配合即可完成一个简单的数据系统.要实现一个支持复选.工具 ...

随机推荐

  1. 什么是 FutureTask?使用 ExecutorService 启动任务?

    在 Java 并发程序中 FutureTask 表示一个可以取消的异步运算.它有启动和取消 运算.查询运算是否完成和取回运算结果等方法.只有当运算完成的时候结果才 能取回,如果运算尚未完成 get 方 ...

  2. 怎么获取 Java 程序使用的内存?堆使用的百分比?

    可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及 最大堆内存.通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间. Runtime.freeMemor ...

  3. 怎样将 GB2312 编码的字符串转换为 ISO-8859-1 编码的 字符串?

    String s1 = "你好"; String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1 ...

  4. session与cookie的区别? 如果客户端禁止 cookie session 还能用吗?

    一.session与cookie的区别 session:Session 是存放在服务器端的,类似于Session结构来存放用户数据,当浏览器 第一次发送请求时,服务器自动生成了一个Session和一个 ...

  5. 去掉win10的命令行

    FluentTerminal 和xshell类似,多个终端在一个页面,比较舒服,可复制,可粘贴 界面: https://github.com/felixse/FluentTerminal 自己去git ...

  6. 数仓建模—OneID

    今天是我在上海租房的小区被封的第三天,由于我的大意,没有屯吃的,外卖今天完全点不到了,中午的时候我找到了一包快过期的肉松饼,才补充了1000焦耳的能量.但是中午去做核酸的时候,我感觉走路有点不稳,我看 ...

  7. 学习JDK之“Future机制==>多线程”

    什么是Future接口 Future是java.util.concurrent.Future,是Java提供的接口,可以用来做异步执行的状态获取,它避免了异步任务在调用者那里阻塞等待,而是让调用者可以 ...

  8. Altium Designer 设置多层方法及各层介绍

    因为PCB板子的层分类有很多,所以通过帮助大家能更好地理解PCB的结构,所以把我所知道的跟大家分享一下 1.PCB各层简介 1. Top Layer顶层布线层(顶层的走线) 2. Bottom Lay ...

  9. 从CSS盒子模型说起

    前言 总括: 对于盒子模型,BFC,IFC和外边距合并等概念和问题的总结 原文地址:从CSS盒子模型说起 知乎专栏:前端进击者 博主博客地址:Damonare的个人博客 为学之道,莫先于穷理:穷理之要 ...

  10. 来扯点ionic3[7] LocalStorage的使用—以登录和注销为例

    一般意义上,一个互联网 APP 中的数据主自与服务器的交互,但是对于有些数据,我们希望获取到它们以后能保存,并在全局环境使用,比如用户数据--我们不希望在每个页面都从服务器拉取一遍.这时我们就可以利用 ...