题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4127

题解

首先区间绝对值和可以转化为 \(2\) 倍的区间正数和 \(-\) 区间和。于是问题就转化为区间正数和。

因为每一次增加的量 \(d \geq 0\),所以每一个数只会被从负数变成正数一次。也就是说,从负变正的操作最多出现 \(n\) 次。

于是我们考虑在线段树上对于从负数变成正数的操作暴力修改。

如何判断一个区间内有负数变成正数的操作呢。令 \(c\) 表示这个区间的最大负数。于是如果 \(-k \leq c \leq 0\) 那么说明区间有数从负变正。

那么每一次从负变正都会走 \(\log n\) 个线段树节点,于是所有数从负变正而来的总时间为 \(O(n\log n)\)。

其余的修改的复杂度为 \(O(q\log n)\)。


时间复杂度为 \(O((n+q)\log n)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} #define lc o << 1
#define rc o << 1 | 1 const int N = 1e5 + 7;
const ll INF = 0x3f3f3f3f3f3f3f3f; int n, m, dfc;
int a[N];
int dep[N], f[N], siz[N], son[N], dfn[N], pre[N], top[N]; struct Edge { int to, ne; } g[N << 1]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); } struct Node { ll sum, add, sumc, maxf; int s; } t[N << 2];
inline void pushup(int o, int L, int R) {
t[o].s = t[lc].s + t[rc].s;
t[o].sum = t[lc].sum + t[rc].sum + t[o].add * (R - L + 1);
t[o].sumc = t[lc].sumc + t[rc].sumc + t[o].add * t[o].s;
t[o].maxf = -INF;
if (t[lc].maxf) smax(t[o].maxf, t[lc].maxf);
if (t[rc].maxf) smax(t[o].maxf, t[rc].maxf);
if (t[o].maxf == -INF) t[o].maxf = 0;
t[o].maxf && (t[o].maxf += t[o].add);
// dbg("o = %d, L = %d, R = %d, t[o].maxf = %lld, t[o].s = %d\n", o, L, R, t[o].maxf, t[o].s);
assert(t[o].maxf || (t[o].maxf == 0 && t[o].s == R - L + 1));
}
inline void pushdown(int o, int L, int R) {
if (!t[o].add) return;
int M = (L + R) >> 1;
t[lc].sum += t[o].add * (M - L + 1), t[lc].add += t[o].add;
t[lc].sumc += t[o].add * t[lc].s, t[lc].maxf && (t[lc].maxf += t[o].add);
t[rc].sum += t[o].add * (R - M), t[rc].add += t[o].add;
t[rc].sumc += t[o].add * t[rc].s, t[rc].maxf && (t[rc].maxf += t[o].add);
t[o].add = 0;
}
inline void build(int o, int L, int R) {
t[o].add = 0;
if (L == R) {
t[o].sum = a[pre[L]];
t[o].maxf = std::min(0, a[pre[L]]);
t[o].sumc = std::max(a[pre[L]], 0);
t[o].s = a[pre[L]] >= 0;
return;
}
int M = (L + R) >> 1;
build(lc, L, M), build(rc, M + 1, R);
pushup(o, L, R);
}
inline void qadd(int o, int L, int R, int l, int r, int k) {
// dbg("qadd : o = %d, L = %d, R = %d, l = %d, r = %d, k = %d, t[o].maxf = %lld, t[o].sum = %lld, t[o].sumc = %lld, t[o].s = %d, t[o].add = %lld\n", o, L, R, l, r, k, t[o].maxf, t[o].sum, t[o].sumc, t[o].s, t[o].add);
if (l <= L && R <= r && (!t[o].maxf || t[o].maxf < -k)) {
t[o].sum += k * (ll)(R - L + 1);
t[o].sumc += k * (ll)t[o].s;
t[o].add += k;
if (t[o].maxf) t[o].maxf += k;
return;
}
if (L == R) {
t[o].sum += k, t[o].add += k;
t[o].sumc = std::max(0ll, t[o].sum);
t[o].s = t[o].sum >= 0;
t[o].maxf = std::min(0ll, t[o].sum);
return;
}
int M = (L + R) >> 1;
pushdown(o, L, R);
if (l <= M) qadd(lc, L, M, l, r, k);
if (r > M) qadd(rc, M + 1, R, l, r, k);
pushup(o, L, R);
}
inline ll qsum(int o, int L, int R, int l, int r) {
// dbg("qsum : o = %d, L = %d, R = %d, l = %d, r = %d\n", o, L, R, l, r);
if (l <= L && R <= r) return t[o].sumc * 2 - t[o].sum;
int M = (L + R) >> 1;
pushdown(o, L, R);
if (r <= M) return qsum(lc, L, M, l, r);
if (l > M) return qsum(rc, M + 1, R, l, r);
return qsum(lc, L, M, l, r) + qsum(rc, M + 1, R, l, r);
} inline void upd(int x, int y, int k) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) std::swap(x, y);
qadd(1, 1, n, dfn[top[x]], dfn[x], k);
x = f[top[x]];
}
if (dep[x] > dep[y]) std::swap(x, y);
qadd(1, 1, n, dfn[x], dfn[y], k);
}
inline ll qry(int x, int y) {
ll ans = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) std::swap(x, y);
ans += qsum(1, 1, n, dfn[top[x]], dfn[x]);
x = f[top[x]];
}
if (dep[x] > dep[y]) std::swap(x, y);
return ans += qsum(1, 1, n, dfn[x], dfn[y]);
} inline void dfs1(int x, int fa = 0) {
dep[x] = dep[fa] + 1, f[x] = fa, siz[x] = 1;
for fec(i, x, y) if (y != fa) dfs1(y, x), siz[x] += siz[y], siz[y] > siz[son[x]] && (son[x] = y);
}
inline void dfs2(int x, int pa) {
// dbg("x = %d, pa = %d\n", x, pa);
top[x] = pa, dfn[x] = ++dfc, pre[dfc] = x;
if (!son[x]) return; dfs2(son[x], pa);
for fec(i, x, y) if (y != son[x] && y != f[x]) dfs2(y, y);
} inline void work() {
dfs1(1), dfs2(1, 1), build(1, 1, n);
while (m--) {
int opt, x, y, z;
read(opt), read(x), read(y);
if (opt == 1) read(z), upd(x, y, z);
else printf("%lld\n", qry(x, y));
}
} inline void init() {
read(n), read(m);
for (int i = 1; i <= n; ++i) read(a[i]);
int x, y;
for (int i = 1; i < n; ++i) read(x), read(y), adde(x, y);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

bzoj4127 Abs 树链剖分+线段树+均摊分析的更多相关文章

  1. 【bzoj4127】Abs 树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  2. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  4. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  5. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  6. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  7. 【bzoj3083】遥远的国度 树链剖分+线段树

    题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...

  8. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  9. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  10. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

随机推荐

  1. 模拟vue实现简单的webpack打包

    一.安装nodejs,查看是否安装成功 二.package.json项目初始化 npm init 电脑有node环境,在根目录下运行命令npm init初始化项目,根据提示输入项目相关信息,然后运行. ...

  2. cefsharp 在高DPI下闪烁的问题

    今天有客户朋友说程序在他的surface下界面很闪烁,搜索了相关的资料,初步判定是DPI引起的问题,但也有可能是cefsharp 51版本在WIN10上面没有禁用GPU加速,苦于没有环境测试,所以抱着 ...

  3. OGG-DDL复制

    http://blog.sina.com.cn/s/blog_96d348df0102vg6q.html OGG目前只支持Oracle和TeraData的ddl复制,Oracle数据库能够支持除去数据 ...

  4. Openstack_通用技术_RPC 远程异步调用

    目录 目录 RPC 一个通过 HTTP Request 调用操作函数的 RPC 实现样例 环境 接收 HTTP Request RPC 调用具体的操作函数 测试 RPC RPC: 同一个项目内的不同服 ...

  5. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_2_对象的序列化流_ObjectOutputStream

    创建person对象.生成构造方法全参和无参.getter和setter 抛出异常:没有序列化异常 接口的源码 啥都没有.就起到一个标记的作用 用二进制存的

  6. [转载]Parsing X.509 Certificates with OpenSSL and C

    Parsing X.509 Certificates with OpenSSL and C Zakir Durumeric | October 13, 2013 While OpenSSL has b ...

  7. MVC 源码系列之路由(二)

    MVCParseData和Match方法的实现 ### ParseData 那么首先要了解一下ParseData. //namespace Route public string Url { get ...

  8. 【ABAP系列】SAP ABAP WS_DELIVERY_UPDATE 修改数量、过账日期并发货过账

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP WS_DELI ...

  9. DFS序1

    给一棵有根树,这棵树由编号为1..N的N个结点组成.根结点的编号为R.每个结点都有一个权值,结点i的权值为vi .接下来有M组操作,操作分为两类:1 a x,表示将结点a的权值增加x:2 a,表示求结 ...

  10. Apache httpclient拦截器对请求进行签名

    Apahce httpclient 提供HttpRequestInterceptor和HttpResponseInterceptor两种拦截器分别处理请求和响应数据,下面讲一下如何对http请求进行拦 ...