题面

Sample Input

5 7
2 -1 -3 1 1
1 2
1 3
3 4
3 5
2
1 3 0
2
1 2 1
2
1 1 -3
2

Sample Output

2
4
5
2

HINT

Solution

首先考虑序列上的这个问题: 给定一个序列, 有两种操作

  • 修改一个位置上的值
  • 询问某个区间中的连续段的最大权值和

做法是: 用一个线段树维护这个序列, 每个节点所对应的区间记录以下4个信息:

  • sum表示整个区间的权值和
  • leftMax表示以包含从最左边开始的区间的连续段最大权值和
  • rightMax与上面相反
  • max表示整个区间中连续段最大权值和

则我们可以通过上述信息合并两个区间的信息.

考虑如何转化到树上解决: 我们首先进行树链剖分. 我们用sum[u]记录\(u\)这个点的权值加上以\(u\)的每个字节点为根的连通块的最大权值和. 我们用类似于序列上的方法维护\(sum\)即可. 修改一个点的权值时, 往上跳修改即可.

实现的时候把线段树上的信息合并重载为运算符会比较简洁.

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <set> using namespace std;
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1; char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int N = (int)1e5;
int n;
multiset<int> ans;
struct data
{
int leftMax, rightMax, mx, sum;
inline data() { leftMax = rightMax = mx = sum = 0; }
inline data friend operator +(const data &a, const data &b)
{
data res;
res.sum = a.sum + b.sum;
res.leftMax = max(a.leftMax, a.sum + b.leftMax);
res.rightMax = max(b.rightMax, b.sum + a.rightMax);
res.mx = max(res.leftMax, res.rightMax);
res.mx = max(res.mx, a.mx); res.mx = max(res.mx, b.mx);
res.mx = max(res.mx, a.rightMax + b.leftMax);
return res;
}
};
struct segmentTree
{
data nd[N << 2];
void modify(int u, int L, int R, int pos, int x)
{
if (L == R)
{
nd[u].leftMax = nd[u].rightMax = nd[u].mx = max(0, x);
nd[u].sum = x;
return;
}
if (pos <= L + R >> 1) modify(u << 1, L, L + R >> 1, pos, x);
else modify(u << 1 | 1, (L + R >> 1) + 1, R, pos, x);
nd[u] = nd[u << 1] + nd[u << 1 | 1];
}
inline void modify(int pos, int x) { modify(1, 1, n, pos, x); }
data query(int u, int curL, int curR, int L, int R)
{
if (curL >= L && curR <= R) return nd[u];
int mid = curL + curR >> 1;
data res;
if (L <= mid) res = res + query(u << 1, curL, mid, L, R);
if (R > mid) res = res + query(u << 1 | 1, mid + 1, curR, L, R);
return res;
}
inline data query(int L, int R) { return query(1, 1, n, L, R); }
}seg;
struct tree
{
struct node
{
int w;
vector<int> edg; int pre;
int sz, hvy;
int tp, id, lst;
int sum;
inline node() { edg.clear(); }
}nd[N + 1];
inline void addEdge(int u, int v) { nd[u].edg.push_back(v); nd[v].edg.push_back(u); }
void getSize(int u, int pre)
{
nd[u].pre = pre; nd[u].hvy = -1; nd[u].sz = 1;
for (auto v : nd[u].edg) if (v != pre)
{
getSize(v, u); nd[u].sz += nd[v].sz;
if (nd[u].hvy == -1 || nd[v].sz > nd[nd[u].hvy].sz) nd[u].hvy = v;
}
}
int clk;
int work(int u, int tp)
{
nd[u].tp = tp; nd[u].id = ++ clk;
if (~ nd[u].hvy) work(nd[u].hvy, tp);
else
{
for (int v = u; v != nd[u].tp; v = nd[v].pre) nd[v].lst = nd[u].id;
nd[nd[u].tp].lst = nd[u].id;
}
nd[u].sum = nd[u].w;
for (auto v : nd[u].edg) if (v != nd[u].pre && v != nd[u].hvy) nd[u].sum += work(v, v);
seg.modify(nd[u].id, nd[u].sum);
if (u == tp)
{
data res = seg.query(nd[u].id, nd[u].lst);
ans.insert(res.mx);
return res.leftMax;
}
return 0;
}
inline void decomposition() { getSize(1, -1); clk = 0; work(1, 1); }
inline void modify(int u, int x)
{
int tmp = nd[u].w; nd[u].w = x;
for (; ~ u; u = nd[nd[u].tp].pre)
{
nd[u].sum = nd[u].sum - tmp + x;
data res = seg.query(nd[nd[u].tp].id, nd[nd[u].tp].lst);
tmp = res.leftMax;
ans.erase(ans.find(res.mx));
seg.modify(nd[u].id, nd[u].sum);
res = seg.query(nd[nd[u].tp].id, nd[nd[u].tp].lst);
x = res.leftMax;
ans.insert(res.mx);
}
}
}T;
int main()
{ #ifndef ONLINE_JUDGE freopen("sub.in", "r", stdin);
freopen("sub.out", "w", stdout); #endif using namespace Zeonfai;
n = getInt(); int m = getInt();
for (int i = 1; i <= n; ++ i) T.nd[i].w = getInt();
for (int i = 1, u, v; i < n; ++ i) u = getInt(), v = getInt(), T.addEdge(u, v);
ans.clear();
T.decomposition();
for (int i = 0; i < m; ++ i)
{
int opt = getInt();
if (opt == 1)
{
int u = getInt(), x = getInt();
T.modify(u, x);
}
else
{
multiset<int>::iterator p = ans.end();
printf("%d\n", *(-- p));
}
}
}

NOI模拟题1 Problem A: sub的更多相关文章

  1. NOI模拟题6 Problem C: Circle

    Solution 首先这个矩阵, 很明显的就是Vandermonde矩阵. 我们有公式: \[ |F_n| = \prod_{1 \le j < i \le n} (a_i - a_j) \] ...

  2. NOI模拟题5 Problem A: 开场题

    Solution 注意到\(\gcd\)具有结合律: \[ \gcd(a, b, c) = \gcd(a, \gcd(b, c)) \] 因此我们从后往前, 对于每个位置\(L\), 找到每一段不同的 ...

  3. NOI模拟题4 Problem C: 填格子(board)

    Solution 首先我们要有敏锐的直觉: 我们将每一列中不选哪种颜色看作是一个序列, 则我们发现这个序列要求相邻两位的颜色不同. 我们还发现, 一个这样的序列对应两种不同的合法的棋盘, 因此统计合法 ...

  4. NOI模拟题4 Problem B: 小狐狸(fox)

    Solution 考虑分开统计朝向每一个方向的所有狐狸对答案的贡献. 比如说以向右为例, 我们用箭标表示每一只狐狸的方向, 用\('\)表示当前一步移动之前的每一只狐狸的位置. \[ \begin{a ...

  5. NOI模拟题4 Problem A: 生成树(mst)

    Solution 我们考虑答案的表达式: \[ ans = \sqrt{\frac{\sum_{i = 1}^{n - 1} (w_i - \overline{w})^2}{n - 1}} \] 其中 ...

  6. 花海漫步 NOI模拟题

    题目好像难以看懂? 题目大意 给出一个字符串\(S\),统计满足以下条件的\((i,j,p,q)\)的数量. \(i \leq j, p \leq q\) \(S[i..j],S[p..q]\)是回文 ...

  7. 神奇的矩阵 NOI模拟题

    神奇的矩阵 题目大意 有一个矩阵\(A\),第一行是给出的,接下来第\(x\)行,第\(y\)个元素的值为数字\(A_{x-1,y}\)在\(\{A_{x-1,1},A_{x-1,2},A_{x-1, ...

  8. Western Subregional of NEERC, Minsk, Wednesday, November 4, 2015 Problem K. UTF-8 Decoder 模拟题

    Problem K. UTF-8 Decoder 题目连接: http://opentrains.snarknews.info/~ejudge/team.cgi?SID=c75360ed7f2c702 ...

  9. 2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem I. Interest Targeting 模拟题

    Problem I. Interest Targeting 题目连接: http://codeforces.com/gym/100714 Description A unique display ad ...

随机推荐

  1. jar包导入仓库中

    mvn install:install-file -Dfile=F:/kaptcha-2.3.jar -DgroupId=com.google.code.kaptcha -DartifactId=ka ...

  2. mysql 外连接的时候,条件在on后面和条件在where后面的区别

    最近使用mysql的时候碰到一个问题:当一个表外联另一个表的时候,将一些查询条件放在on后面和放在where后面不太一样: 学生分数表stuscore: 当查询语句如下(查询语句1): SELECT ...

  3. 51、如何提取android代码中的字符串为系统资源文件 (I18N)

    工具:android studio 步骤1:找到要转为资源文件的字符串并选中,同时按下option+enter,弹出菜单,我们选中extract string resource 步骤2:在弹窗中输入你 ...

  4. 33、secret

    CemFjee9rueuoeeQhgkxCee9kee7nO+8jOW6lOeUqO+8jOaVsOaNruW6k+acjeWKoeeahOWFs+mUruS/oeaBr++8iOWmgiDmnI3l ...

  5. [python][django学习篇][4]django完成数据库代码翻译:迁移数据库(migration)

    上一篇我们已经完成数据库的设计,但是仅仅是python语言,并没有真正创建了数据库表.翻译成数据库语言,真正创建数据库表由django manage.py来实现,这一过程专业术语:迁移数据库 切换到m ...

  6. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛

    拖了好久了 链接:https://www.nowcoder.com/acm/contest/90/A来源:牛客网 跳台阶 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K, ...

  7. python 打印9*9乘法表

    # -*- coding: utf8 -*- # Author:wxq 1. for i in range(1,10): for j in range(1,i+1): print "%d*% ...

  8. shell执行mysql的脚本(包括mysql执行shell脚本)

    在Shell中执行mysql的脚本,这里介绍比较容易使用的一种方法 首先写好sql的脚本,后缀为.sql,比如 sql_file.sql:内容如下 #这是SQL的脚本create table if n ...

  9. 【bzoj2529】[Poi2011]Sticks 贪心

    题目描述 给出若干木棍,每根木棍有特定的颜色和长度.问能否找到三条颜色不同的木棍构成一个三角形.(注意这里所说的三角形面积要严格大于0) 输入 第一行给出一个整数k(3<=k<=50),表 ...

  10. Juice Junctions

    Juice Junctions 题目描述 你被雇佣升级一个旧果汁加工厂的橙汁运输系统.系统有管道和节点构成.每条管道都是双向的,且每条管道的流量都是11升每秒.管道可能连接节点,每个节点最多可以连接3 ...