#李超线段树,树链剖分#洛谷 4069 [SDOI2016]游戏
分析
就是把线段扔到了树上,注意区间查询要比较两个端点的函数值,
把区间赋值转换成两部分,从起点到LCA的区间是斜率为负数的线段,
从终点到LCA的区间是斜率为正数的线段。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
typedef long long lll;
const int N = 100011;
struct node {
    int y, w, next;
} e[N << 1];
int p[N << 2], Tot, dep[N], top[N], k = 1, tot, fat[N], nfd[N], dfn[N], son[N], big[N], n, m, as[N];
struct rec {
    lll a, b;
} line[N << 1];
lll dis[N], w[N << 2];
inline signed iut() {
    rr int ans = 0, f = 1;
    rr char c = getchar();
    while (!isdigit(c)) f = (c == '-') ? -f : f, c = getchar();
    while (isdigit(c)) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
    return ans * f;
}
inline void print(lll ans) {
    if (ans < 0)
        ans = -ans, putchar('-');
    if (ans > 9)
        print(ans / 10);
    putchar(ans % 10 + 48);
}
inline lll min(lll a, lll b) { return a < b ? a : b; }
inline lll calc(int t, int x) { return line[t].a * dis[nfd[x]] + line[t].b; }
inline void build(int k, int l, int r) {
    p[k] = 1, w[k] = line[1].b;
    if (l == r)
        return;
    rr int mid = (l + r) >> 1;
    build(k << 1, l, mid);
    build(k << 1 | 1, mid + 1, r);
}
inline void update(int k, int l, int r, int x, int y, int z) {
    rr int mid = (l + r) >> 1;
    if (x <= l && r <= y) {
        rr lll la = calc(p[k], l), lb = calc(z, l);
        rr lll ra = calc(p[k], r), rb = calc(z, r), mb = min(lb, rb);
        if (la <= lb && ra <= rb)
            return;
        if (la >= lb && ra >= rb) {
            p[k] = z, w[k] = min(w[k], mb);
            return;
        }
        rr double pos = 1.0 * (line[p[k]].b - line[z].b) / (line[z].a - line[p[k]].a);
        if (la >= lb) {
            if (pos <= dis[nfd[mid]])
                update(k << 1, l, mid, x, y, z);
            else
                update(k << 1 | 1, mid + 1, r, x, y, p[k]), p[k] = z;
        } else {
            if (pos > dis[nfd[mid]])
                update(k << 1 | 1, mid + 1, r, x, y, z);
            else
                update(k << 1, l, mid, x, y, p[k]), p[k] = z;
        }
        w[k] = min(min(w[k], mb), min(w[k << 1], w[k << 1 | 1]));
        return;
    }
    if (x <= mid)
        update(k << 1, l, mid, x, y, z);
    if (mid < y)
        update(k << 1 | 1, mid + 1, r, x, y, z);
    w[k] = min(w[k], min(w[k << 1], w[k << 1 | 1]));
}
inline signed lca(int x, int y) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            x ^= y, y ^= x, x ^= y;
        x = fat[top[x]];
    }
    if (dep[x] > dep[y])
        x ^= y, y ^= x, x ^= y;
    return x;
}
inline lll query(int k, int l, int r, int x, int y) {
    if (l == x && r == y)
        return w[k];
    rr int mid = (l + r) >> 1;
    rr lll lT = calc(p[k], x), rT = calc(p[k], y), mT = min(lT, rT);
    if (y <= mid)
        return min(mT, query(k << 1, l, mid, x, y));
    else if (x > mid)
        return min(mT, query(k << 1 | 1, mid + 1, r, x, y));
    else
        return min(mT, min(query(k << 1, l, mid, x, mid), query(k << 1 | 1, mid + 1, r, mid + 1, y)));
}
inline void Update(int x, int LCA, int z) {
    for (; top[x] != top[LCA]; x = fat[top[x]]) update(1, 1, n, dfn[top[x]], dfn[x], z);
    update(1, 1, n, dfn[LCA], dfn[x], z);
}
inline lll Query(int x, int y) {
    rr lll ans = line[1].b;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            x ^= y, y ^= x, x ^= y;
        ans = min(ans, query(1, 1, n, dfn[top[x]], dfn[x]));
        x = fat[top[x]];
    }
    if (dep[x] > dep[y])
        x ^= y, y ^= x, x ^= y;
    return ans = min(ans, query(1, 1, n, dfn[x], dfn[y]));
}
inline void dfs1(int x, int fa) {
    dep[x] = dep[fa] + 1, fat[x] = fa, son[x] = 1;
    for (rr int i = as[x], mson = -1; i; i = e[i].next)
        if (e[i].y != fa) {
            dis[e[i].y] = dis[x] + e[i].w, dfs1(e[i].y, x), son[x] += son[e[i].y];
            if (son[e[i].y] > mson)
                big[x] = e[i].y, mson = son[e[i].y];
        }
}
inline void dfs2(int x, int linp) {
    dfn[x] = ++tot, nfd[tot] = x, top[x] = linp;
    if (!big[x])
        return;
    dfs2(big[x], linp);
    for (rr int i = as[x]; i; i = e[i].next)
        if (e[i].y != fat[x] && e[i].y != big[x])
            dfs2(e[i].y, e[i].y);
}
signed main() {
    n = iut();
    m = iut();
    for (rr int i = 1; i < n; ++i) {
        rr int x = iut(), y = iut(), w = iut();
        e[++k] = (node){ y, w, as[x] }, as[x] = k;
        e[++k] = (node){ x, w, as[y] }, as[y] = k;
    }
    line[Tot = 1] = (rec){ 0, 123456789123456789ll };
    dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
    for (rr int i = 1; i <= m; ++i)
        if (iut() & 1) {
            rr int x = iut(), y = iut(), A = iut(), B = iut(), LCA = lca(x, y);
            line[++Tot] = (rec){ -A, dis[x] * A + B }, Update(x, LCA, Tot);
            line[++Tot] = (rec){ A, (dis[x] - dis[LCA] * 2) * A + B }, Update(y, LCA, Tot);
        } else
            print(Query(iut(), iut())), putchar(10);
    return 0;
}
#李超线段树,树链剖分#洛谷 4069 [SDOI2016]游戏的更多相关文章
- 洛谷P4069 [SDOI2016]游戏(李超线段树)
		题意 题目链接 Sol 这题细节好多啊qwq..稍不留神写出一个小bug就要调1h+.. 思路就不多说了,把询问区间拆成两段就是李超线段树板子题了. 关于dis的问题可以直接维护. // luogu- ... 
- 洛谷P4069 [SDOI2016]游戏(李超线段树)
		题面 传送门 题解 如果我们把路径拆成两段,那么这个路径加可以看成是一个一次函数 具体来说,设\(dis_u\)表示节点\(u\)到根节点的距离,那么\((x,lca)\)这条路径上每个节点的权值就会 ... 
- AC日记——【模板】树链剖分 洛谷 P3384
		题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ... 
- 洛谷 P2197 nim游戏
		洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ... 
- 洛谷 P1965 转圈游戏
		洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ... 
- 洛谷 P4072 [SDOI2016]征途 斜率优化DP
		洛谷 P4072 [SDOI2016]征途 斜率优化DP 题目描述 \(Pine\) 开始了从 \(S\) 地到 \(T\) 地的征途. 从\(S\)地到\(T\)地的路可以划分成 \(n\) 段,相 ... 
- 李超线段树(segment[HEOI2013]-洛谷T4097)
		(neng了好久好久才糊弄懂得知识点...) 一.李超线段树 在线动态维护一个二维平面直角坐标系, 支持插入一条线段, 询问与直线x = x0相交的所有线段中,交点y的最大/小值 (若有多条线段符合条 ... 
- 树剖模板(洛谷P3384 【模板】树链剖分)(树链剖分,树状数组,树的dfn序)
		洛谷题目传送门 仍然是一个板子. 不过蒟蒻去学了一下BIT维护区间修改区间求和,常数果真十分优秀 设数列为\(a_i\),差分数组\(d_ i=a_ i-a_ {i-1}\),前缀和\(s_i=\su ... 
- 线段树分治初步学习&洛谷P5227[AHOI2013]连通图
		线段树分治 其实思想说起来是比较简单的,我们把这个题里的所有操作(比如连边删边查询balabala)全部拍到一棵线段树上,然后对着整棵树dfs一下求解答案,顺便把操作做一下,回溯的时候撤销一下即可.虽 ... 
- 线段树&数链剖分
		傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ... 
随机推荐
- OsgEarth开发笔记(二):Osg3.6.3+OsgEarth3.1+vs2019x64开发环境搭建(中)
			上一篇:<OsgEarth开发笔记(一):Osg3.6.3+OsgEarth3.1+vs2019x64开发环境搭建(上)>下一篇:敬请期待- 前言 上一篇编译了osg和osgCurl ... 
- zlib开发笔记(一):zlib库介绍、编译和工程模板
			前言 Qt使用一些压缩解压功能,介绍过libzip库编译,本篇说明zlib库. zlib库 zlib被设计为一个免费的,通用的,法律上不受限制的-即不受任何专利保护的无损数据压缩库,几乎可 ... 
- http.Handler接口
			// 示例 // net/http package http type Handler interface{ ServeHTTP(w ResponseWriter, r *Request) } fun ... 
- xadmin后台的安装及配置使用
			安装 pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2 在settings.py中注册如下应用 INSTALLED_ ... 
- Android底层渲染原理
			Overview多年前Android的UI流畅性差的问题一直饱受诟病,Google为了解决这个问题开发了Project Butter项目,也就是黄油计划,期望彻底改善Android系统的流畅性.这是A ... 
- Linux或者Mac解压乱码问题
			1.unar : 命令行解压工具 2.安装: ubuntu等Linux安装方法:sudo apt install unar mac系统安装方法:brew install unar 现在mac电脑用 T ... 
- 【Azure 事件中心】如何查看事件中心的消息中具体报文内容呢?
			问题描述 如何查看事件中心的消息中具体报文内容呢? 问题解答 正常情况是通过 Event Hub 的消费端获取消息进行处理查看,但是没有客户端代码的情况下,也可以通过微软的默认客户端Service B ... 
- Nebula Graph 的 KV 存储分离原理和性能测评
			本文首发于 Nebula Graph Community 公众号 1. 概述 过去十年,图计算无论在学术界还是工业界热度持续升高.相伴而来的是,全世界的数据正以几何级数形式增长.在这种情况下,对于数据 ... 
- CXPACKET等待类型分析
			背景 客户反馈今天8点钟开始进入业务高峰期后,数据库的CPU利用率非常高,基本达到了100%,前端应用也非常慢.怀疑是昨晚业务系统升级导致,请我们紧急协助分析. 现象 登录到SQL专家云,进入相关时间 ... 
- 痞子衡嵌入式:使用恩智浦GUI Guider快速创建全新LCD屏示例工程的步骤
			大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是使用恩智浦GUI Guider快速创建全新LCD屏示例工程的步骤. 在痞子衡旧文 <在i.MXRT1170上快速点亮一款全新LCD ... 
