「CF1110F」Nearest Leaf

• 遇到一个节点，我们就把子树内 $$-$$，子树外 $$+$$，然后直接处理查询。
• 线段树维护区间加和区间最小值。
• 注意极大值的取值，注意回溯的时候要复原。

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long LL;
LL Abs (LL x) { return x < 0 ? -x : x; }
LL Max (LL x, LL y) { return x > y ? x : y; }
LL Min (LL x, LL y) { return x < y ? x : y; }

int Read () {
int x = 0, k = 1;
char s = getchar ();
while (s < '0' || s > '9') {
if (s == '-')
k = -1;
s = getchar ();
}
while ('0' <= s && s <= '9')
x = (x << 3) + (x << 1) + (s ^ 48), s = getchar ();
return x * k;
}

void Write (LL x) {
if (x < 0)
putchar ('-'), x = -x;
if (x > 9)
Write (x / 10);
putchar (x % 10 + '0');
}

void Print (LL x, char s) { Write (x), putchar (s); }

const LL Inf = 1e16;
const int Maxn = 5e5 + 5;

struct Segment_Tree {
struct Segment_Node {
int l, r;
LL Lazy, Val;
#define Lson p << 1
#define Rson p << 1 | 1
Segment_Node () {}
Segment_Node (int L, int R, LL La, LL V) { l = L, r = R, Lazy = La, Val = V; }
} Tr[Maxn << 2];

void Make_Tree (int p, int l, int r) {
Tr[p].Val = Inf, Tr[p].l = l, Tr[p].r = r, Tr[p].Lazy = 0;
if (l == r)
return ;
int Mid = (l + r) >> 1;
Make_Tree (Lson, l, Mid), Make_Tree (Rson, Mid + 1, r);
}

void Pull (int p) { Tr[p].Val = Min (Tr[Lson].Val, Tr[Rson].Val); }

void Push (int p) {
if (Tr[p].Lazy) {
Tr[Lson].Val += Tr[p].Lazy, Tr[Rson].Val += Tr[p].Lazy;
Tr[Lson].Lazy += Tr[p].Lazy, Tr[Rson].Lazy += Tr[p].Lazy;
Tr[p].Lazy = 0;
}
}

void Update (int p, int l, int r, LL x) {
if (l <= Tr[p].l && Tr[p].r <= r) {
Tr[p].Lazy += x, Tr[p].Val += x;
return ;
}
Push (p);
int Mid = (Tr[p].l + Tr[p].r) >> 1;
if (l <= Mid)
Update (Lson, l, r, x);
if (r > Mid)
Update (Rson, l, r, x);
Pull (p);
}

LL Query (int p, int l, int r) {
if (l <= Tr[p].l && Tr[p].r <= r)
return Tr[p].Val;
Push (p);
LL Res = Inf;
int Mid = (Tr[p].l + Tr[p].r) >> 1;
if (l <= Mid)
Res = Min (Res, Query (Lson, l, r));
if (r > Mid)
Res = Min (Res, Query (Rson, l, r));
return Res;
}

#undef Lson
#undef Rson
} Tree;

struct Query {
int l, r, Id;
Query () {}
Query (int L, int R, int I) { l = L, r = R, Id = I; }
};

struct Edge {
int v, w;
Edge () {}
Edge (int V, int W) { v = V, w = W; }
friend bool operator < (Edge x, Edge y) { return x.v < y.v; }
};

int Size[Maxn], n, m;
LL Res[Maxn], Dep[Maxn];
vector <Query> q[Maxn];
vector <Edge> Graph[Maxn];

void Add_Edge (int u, int v, int w) { Graph[u].push_back (Edge (v, w)); }

void Dfs (int u) {
Size[u] = 1;
for (int i = 0, v; i < Graph[u].size (); i++)
v = Graph[u][i].v, Dep[v] = Dep[u] + Graph[u][i].w, Dfs (v), Size[u] += Size[v];
if (Graph[u].size () == 0)
Tree.Update (1, u, u, Dep[u] - Inf);
}

void Calc (int u) {
for (int i = 0; i < q[u].size (); i++)
Res[q[u][i].Id] = Tree.Query (1, q[u][i].l, q[u][i].r);
for (int i = 0, v, w; i < Graph[u].size (); i++) {
v = Graph[u][i].v, w = Graph[u][i].w;
Tree.Update (1, v, v + Size[v] - 1, -w);
if (v > 1)
Tree.Update (1, 1, v - 1, w);
if (v + Size[v] - 1 < n)
Tree.Update (1, v + Size[v], n, w);
Calc (v);
Tree.Update (1, v, v + Size[v] - 1, w);
if (v > 1)
Tree.Update (1, 1, v - 1, -w);
if (v + Size[v] - 1 < n)
Tree.Update (1, v + Size[v], n, -w);
}
}

int main () {
n = Read (), m = Read ();
for (int i = 2, p, w; i <= n; i++)
p = Read (), w = Read (), Add_Edge (p, i, w);
for (int i = 1; i <= n; i++)
sort (Graph[i].begin (), Graph[i].end ());
for (int i = 1, x, l, r; i <= m; i++)
x = Read (), l = Read (), r = Read (), q[x].push_back (Query (l, r, i));
Tree.Make_Tree (1, 1, n), Dfs (1), Calc (1);
for (int i = 1; i <= m; i++)
Print (Res[i], '\n');
return 0;
}


「CF633F」The Chocolate Spree

• 对于 Dp[u][0]

• $$v$$ 选了两条，直接更新， Dp[u][0] = Max (Dp[u][0], Dp[v][0])
• $$v$$ 选了一条，故 $$u$$ 再选一条， Dp[u][0] = Max (Dp[u][0], Dp[v][1] + Dp[u][1])
• $$v$$ 选了两条其中一条端点是 $$v$$，扩展， Dp[u][0] = Max (Dp[u][0], Dp[v][2] + w[u])
• $$v$$ 选了一条且端点是 $$v$$，扩展，Dp[u][0] = Max (Dp[u][0], Dp[v][3] + w[u] + Dp[u][1] - w[u])
• 可以两条接起来一条，Dp[u][0] = Max (Dp[u][0], Max (Dp[v][2] + Dp[u][3], Dp[u][2] + Dp[v][3])
• 对于 Dp[u][1]
• $$v$$ 选了一条，直接更新， Dp[u][1] = Max (Dp[u][1], Dp[v][1])
• $$v$$ 选了一条且端点是 $$v$$，扩展， Dp[u][1] = Max (Dp[u][1], Dp[v][3] + w[u])
• 可以两条接起来，Dp[u][0] = Max (Dp[u][0], Dp[v2][3] + Dp[v2][3] + w[u])
• 对于 Dp[u][2]
• $$v$$ 选了一条，则 $$u$$ 再选一条端点是 $$u$$，Dp[u][2] = Max (Dp[u][2], Dp[v][1] + Dp[u][3])
• $$v$$ 选了两条且其中一条端点是 $$v$$，扩展，Dp[u][2] = Max (Dp[u][2], Dp[v][2] + w[u])
• $$v$$ 选了一条且端点是 $$v$$，扩展然后再选一条，或者不扩展再选一条端点为 $$u$$，Dp[u][2] = Max (Dp[u][2], Max (Dp[v][3] + w[u] + Dp[u][1] - w[u], Dp[v][3] + Dp[u][3]))
• 对于 Dp[u][3]
• $$v$$ 选了一条且端点是 $$v$$，扩展，Dp[u][3] = Max (Dp[u][3], Dp[v][3] + w[u])

#include <cstdio>
#include <vector>
using namespace std;

typedef long long LL;
LL Abs (LL x) { return x < 0 ? -x : x; }
LL Max (LL x, LL y) { return x > y ? x : y; }
LL Min (LL x, LL y) { return x < y ? x : y; }

int Read () {
int x = 0, k = 1;
char s = getchar ();
while (s < '0' || s > '9') {
if (s == '-')
k = -1;
s = getchar ();
}
while ('0' <= s && s <= '9')
x = (x << 3) + (x << 1) + (s ^ 48), s = getchar ();
return x * k;
}

void Write (LL x) {
if (x < 0)
putchar ('-'), x = -x;
if (x > 9)
Write (x / 10);
putchar (x % 10 + '0');
}

void Print (LL x, char s) { Write (x), putchar (s); }

const int Maxn = 1e5 + 5;

int w[Maxn];
LL Dp[Maxn][4];
vector <int> Graph[Maxn];

void Add_Edge (int u, int v) { Graph[u].push_back (v), Graph[v].push_back (u); }

void Tree_Dp (int u, int Fa) {
Dp[u][1] = Dp[u][3] = w[u];
LL Fir = 0, Sec = 0, Ma = 0;
for (int i = 0, v; i < Graph[u].size (); i++) {
v = Graph[u][i];
if (v == Fa)
continue;
Tree_Dp (v, u);
Dp[u][0] = Max (Dp[u][0], Dp[v][0]);
Dp[u][0] = Max (Dp[u][0], Dp[v][1] + w[u]);
Dp[u][0] = Max (Dp[u][0], Dp[v][2] + w[u]);
Dp[u][0] = Max (Dp[u][0], Dp[v][3] + w[u]);
if (i > 0) {
Dp[u][0] = Max (Dp[u][0], Dp[v][1] + Dp[u][1]);
Dp[u][0] = Max (Dp[u][0], Dp[v][1] + Dp[u][3]);
if (Ma)
Dp[u][0] = Max (Dp[u][0], Ma + w[u] + Dp[v][3]);
Dp[u][0] = Max (Dp[u][0], Dp[v][2] + Dp[u][3]);
Dp[u][0] = Max (Dp[u][0], Dp[v][3] + Dp[u][1]);
Dp[u][0] = Max (Dp[u][0], Dp[v][3] + Dp[u][3]);
Dp[u][0] = Max (Dp[u][0], Dp[v][3] + Dp[u][2]);
}
Dp[u][2] = Max (Dp[u][2], Dp[v][1] + w[u]);
Dp[u][2] = Max (Dp[u][2], Dp[v][2] + w[u]);
Dp[u][2] = Max (Dp[u][2], Dp[v][3] + w[u]);
if (i > 0) {
Dp[u][2] = Max (Dp[u][2], Dp[v][1] + Dp[u][3]);
if (Ma)
Dp[u][2] = Max (Dp[u][2], Ma + w[u] + Dp[v][3]);
Dp[u][2] = Max (Dp[u][2], Dp[v][3] + Dp[u][3]);
}
if (Dp[v][1] > Ma)
Ma = Dp[v][1];
if (Dp[v][3] > Fir)
Sec = Fir, Fir = Dp[v][3];
else if (Dp[v][3] > Sec)
Sec = Dp[v][3];
if (Fir && Sec)
Dp[u][1] = Max (Dp[u][1], Fir + Sec + w[u]);
Dp[u][1] = Max (Dp[u][1], Dp[v][1]);
Dp[u][1] = Max (Dp[u][1], Dp[v][3] + w[u]);
Dp[u][3] = Max (Dp[u][3], Dp[v][3] + w[u]);
}
}

int main () {
int n = Read ();
for (int i = 1; i <= n; i++)
w[i] = Read ();
for (int i = 1, u, v; i < n; i++)
u = Read (), v = Read (), Add_Edge (u, v);
Tree_Dp (1, -1);
// for (int i = 1; i <= n; i++)
//     printf ("%lld %lld %lld %lld\n", Dp[i][0], Dp[i][1], Dp[i][2], Dp[i][3]);
Print (Dp[1][0], '\n');
return 0;
}


「CF1120D」Power Tree

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long LL;
int Abs (int x) { return x < 0 ? -x : x; }
int Max (int x, int y) { return x > y ? x : y; }
int Min (int x, int y) { return x < y ? x : y; }

int Read () {
int x = 0, k = 1;
char s = getchar ();
while (s < '0' || s > '9') {
if (s == '-')
k = -1;
s = getchar ();
}
while ('0' <= s && s <= '9')
x = (x << 3) + (x << 1) + (s ^ 48), s = getchar ();
return x * k;
}

void Write (LL x) {
if (x < 0)
putchar ('-'), x = -x;
if (x > 9)
Write (x / 10);
putchar (x % 10 + '0');
}

void Print (LL x, char s) { Write (x), putchar (s); }

const int Inf = 1e9;
const int Maxn = 2e5 + 5;

struct Node {
int l, r;
Node () {}
Node (int L, int R) { l = L, r = R; }
} q[Maxn];

struct Edge {
int u, v, w, Pos;
Edge () {}
Edge (int U, int V, int W, int P) { u = U, v = V, w = W, Pos = P; }
friend bool operator < (Edge x, Edge y) { return x.w < y.w; }
} e[Maxn];

bool Vis[Maxn];
vector <int> Graph[Maxn];
int w[Maxn], Dfn[Maxn], Fa[Maxn], Cnt;

void Add_Edge (int u, int v) { Graph[u].push_back (v), Graph[v].push_back (u); }

void Make_Tree (int n) {
for (int i = 1; i <= n; i++)
Fa[i] = i;
}

int Find_Set (int x) { return Fa[x] == x ? x : Fa[x] = Find_Set (Fa[x]); }

void Dfs (int u, int Fa) {
q[u].l = Inf, q[u].r = -Inf;
for (int i = 0, v; i < Graph[u].size (); i++) {
v = Graph[u][i];
if (v == Fa)
continue;
Dfs (v, u), q[u].l = Min (q[u].l, q[v].l), q[u].r = Max (q[u].r, q[v].r);
}
if (Graph[u].size () == 1 && u != 1)
q[u].l = q[u].r = ++Cnt;
e[u] = Edge (q[u].l, q[u].r + 1, w[u], u);
}

int main () {
int n = Read ();
for (int i = 1; i <= n; i++)
w[i] = Read ();
for (int i = 1, u, v; i < n; i++)
u = Read (), v = Read (), Add_Edge (u, v);
Dfs (1, -1), sort (e + 1, e + n + 1);
Make_Tree (Cnt + 1), Cnt++;
LL Res = 0;
int Tot = 0;
for (int l = 1, r; l <= n; l = r + 1) {
r = l;
while (r + 1 <= n && e[r].w == e[r + 1].w)
r++;
for (int i = l, u, v; i <= r; i++) {
u = Find_Set (e[i].u), v = Find_Set (e[i].v);
if (u != v)
Vis[e[i].Pos] = true, Tot++;
}
for (int i = l, u, v; i <= r; i++) {
u = Find_Set (e[i].u), v = Find_Set (e[i].v);
if (u != v)
Fa[v] = u, Res += e[i].w;
}
}
Print (Res, ' '), Print (Tot, '\n');
for (int i = 1; i <= n; i++)
if (Vis[i])
Print (i, ' ');
putchar ('\n');
return 0;
}


Solution -「树上杂题？」专练的更多相关文章

1. LOJ6003 - 「网络流 24 题」魔术球

原题链接 Description 假设有根柱子,现要按下述规则在这根柱子中依次放入编号为的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法 ...

2. LOJ6002 - 「网络流 24 题」最小路径覆盖

原题链接 Description 求一个DAG的最小路径覆盖,并输出一种方案. Solution 模板题啦~ Code //「网络流 24 题」最小路径覆盖 #include <cstdio&g ...

3. LOJ6001 - 「网络流 24 题」太空飞行计划

原题链接 Description 有个实验和个仪器,做实验有报酬买仪器有花费.每个实验都需要一些仪器,求最大净收益(实验报酬仪器花费),并输出一组方案. Solution 实验向所需仪器连边,实验的点 ...

4. Libre 6006 「网络流 24 题」试题库 / Luogu 2763 试题库问题 （网络流，最大流）

Libre 6006 「网络流 24 题」试题库 / Luogu 2763 试题库问题 (网络流,最大流) Description 问题描述: 假设一个试题库中有n道试题.每道试题都标明了所属类别.同 ...

5. loj #6122. 「网络流 24 题」航空路线问题

#6122. 「网络流 24 题」航空路线问题 题目描述 给定一张航空图,图中顶点代表城市,边代表两个城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. 从最西端城市出发,单 ...

6. [LOJ#6002]「网络流 24 题」最小路径覆盖

[LOJ#6002]「网络流 24 题」最小路径覆盖 试题描述 给定有向图 G=(V,E).设 P 是 G 的一个简单路(顶点不相交)的集合.如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是  ...

7. liberOJ#6006. 「网络流 24 题」试题库 网络流， 输出方案

#6006. 「网络流 24 题」试题库     题目描述 假设一个试题库中有 n nn 道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取 m mm 道题组成试卷.并要求 ...

8. LOJ6000 - 「网络流 24 题」搭配飞行员

原题链接 题意简述 求二分图的最大匹配. 题解 这里写的是匈牙利算法. 表示节点的当前匹配. 为真表示在这一轮匹配中,无法给节点一个新的匹配.所以如果为真就不用再dfs它了,直接continue就好. ...

9. LibreOJ #6014. 「网络流 24 题」最长 k 可重区间集

#6014. 「网络流 24 题」最长 k 可重区间集 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   ...

随机推荐

1. 完全卸载nginx的详细步骤

一个执着于技术的公众号 前言 在开局配置Nginx时有可能会配置错误,报各种错误代码.看不懂或者懒得去看这个报错时,其实最简单的方式是卸载并重装咯.今天就带大家一起学习下,如何彻底卸载nginx程序. ...

2. uniapp中IOS安卓热更新和整包更新app更新

在App.vue中 onLaunch: function() { console.log('App Launch'); // #ifdef APP-PLUS this.getVersion(); // ...

3. 使用VLL技术实现多家合作伙伴复用同一条链路做两端数据全透传

公司A当前租用一条10G跨市运营商光缆,自身业务只用到一半流量,为节省成本,寻求多家合作伙伴共用链路以达到财务需求 合作伙伴需求接入链路全透传,即光缆两端接入点端口逻辑直连 当前有三种方案可以实现上述 ...

4. mybatis plus 更新字段的时候设置为 null 后不生效

mybatis plus 将属性设置为 null 值会被忽略,最终生成的 sql 中不会有 set field = null(可能是某些情况) mybatis-plus 更新字段的时候设置为 null ...

5. 【算法】堆排序（Heap Sort）（七）

堆排序(Heap Sort) 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父 ...

6. 技术分享 | 云原生多模型 NoSQL 概述

作者 朱建平,TEG/云架构平台部/块与表格存储中心副总监.08年加入腾讯后,承担过对象存储.键值存储,先后负责过KV存储-TSSD.对象存储-TFS等多个存储平台. NoSQL 技术和行业背景 No ...

7. 好客租房1-React基础目标

学习目标 能够说出React是什么 掌握react的特点 掌握react的基本使用 能够使用react脚手架 学习目录 react概述 react基本使用 react脚手架

8. 139_Power BI之某制造企业HR相关数据年度复盘

博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 最近在忙一个关于制造企业HR年度数据复盘分析:数据已脱敏. 先来看看效果. 1.视频效果 [video widt ...

9. babel使用

Babel转码器 Babel定义 Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在老版本的浏览器执行 Babel安装 仅需要在项目文件下安装 npm ins ...

10. 给IDEA道个歉，这不是它的BUG，而是反编译插件的BUG。

你好呀,我是歪歪. 上周我不是发了<我怀疑这是IDEA的BUG,但是我翻遍全网没找到证据!>这篇文章吗. 主要描述了在 IDEA 里面反编译后的 class 文件中有这样的代码片段: 很明 ...