BZOJ 4515

树链剖分 + 李超线段树

要求支持区间插入一条线段,然后查询一个区间内的最小值。可以使用李超线段树解决,因为要维护一个区间内的最小值,所以每一个结点再维护一个$res$表示这个区间内的最小值。因为本题把问题搬到了树上,剖一下就可以了。

我们可以把一个点$x$到根的距离$dis_x$记为一个点在二维平面上的横坐标,这样子可以保证一条重链上的点的距离递增,并且不改变点之间的距离。

考虑到一条树链$(x, y, z)$($z$是$lca(x, y)$)上的数字的覆盖情况是先从$x$向上走到$z$,然后从$z$向下走走到$y$,向上走的时候直线的斜率是$-k$,而向下走的时候直线的斜率是$k$,所以我们把一条树链拆成两条线段插入。

现在记录剩下的我写错的地方:

1、链剖的$dfs2$写错了,一定要注意先向下剖分重儿子。

2、在写线段树的时候要注意要求出来的线段交点的坐标其实是没有离散化过的值,需要拿它和中间的坐标的原来的值进行比较。

3、在求最小的时候注意上层的结点的区间可能包含了我们要求的区间,而这时候上层结点的$res$并不能拿来直接使用(可能会使答案变小),需要根据保存的直线的解析式重新计算。

时间复杂度$O(nlog^3n)$,然后只要相信它常数很小就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db; const int N = 1e5 + ;
const ll Val0 = 123456789123456789LL; int n, qn, tot = , head[N];
int dfsc = , id[N], pos[N], fa[N], top[N], dep[N], siz[N], son[N];
ll dis[N], kk[N << ], bb[N << ]; struct Edge {
int to, nxt;
ll val;
} e[N << ]; inline void add(int from, int to, ll val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void chkMin(T &x, T y) {
if(y < x) x = y;
} void dfs1(int x, int fat, int depth, ll nowDis) {
fa[x] = fat, dep[x] = depth, siz[x] = , dis[x] = nowDis;
int maxson = -;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs1(y, x, depth + , nowDis + e[i].val); siz[x] += siz[y];
if(siz[y] > maxson)
maxson = siz[y], son[x] = y;
}
} void dfs2(int x, int topf) {
top[x] = topf, pos[id[x] = ++dfsc] = x;
if(!son[x]) return;
dfs2(son[x], topf);
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x] || y == son[x]) continue;
dfs2(y, y);
}
} inline int getLca(int x, int y) {
for(; top[x] != top[y]; ) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return dep[x] > dep[y] ? y : x;
} /* inline ll getDis(int x, int y) {
ll z = getLca(x, y);
return dis[x] + dis[y] - 2 * dis[z];
} */ namespace SegT {
struct Node {
int id;
ll res;
} s[N << ]; #define lc p << 1
#define rc p << 1 | 1
#define mid ((l + r) >> 1)
#define res(p) s[p].res inline void up(int p) {
// res(p) = Val0;
chkMin(res(p), res(lc)), chkMin(res(p), res(rc));
} void build(int p, int l, int r) {
res(p) = Val0, s[p].id = ;
if(l == r) return; build(lc, l, mid);
build(rc, mid + , r);
} void ins(int p, int l, int r, int x, int y, int nid) {
if(x <= l && y >= r) {
/* if(!s[p].cov) {
s[p].cov = 1;
s[p].id = nid;
chkMin(res(p), min(l1, r1));
return;
} */ ll l1 = kk[nid] * dis[pos[l]] + bb[nid], r1 = kk[nid] * dis[pos[r]] + bb[nid];
ll l2 = kk[s[p].id] * dis[pos[l]] + bb[s[p].id], r2 = kk[s[p].id] * dis[pos[r]] + bb[s[p].id];
if(l1 >= l2 && r1 >= r2) return;
if(l1 <= l2 && r1 <= r2) {
s[p].id = nid;
chkMin(res(p), min(l1, r1));
return;
} db loc = 1.0 * (bb[nid] - bb[s[p].id]) / (kk[s[p].id] - kk[nid]);
db md = (db) dis[pos[mid]];
if(l1 > l2) {
if(loc > md) ins(rc, mid + , r, x, y, nid);
else ins(lc, l, mid, x, y, s[p].id), s[p].id = nid;
} else {
if(loc > md) ins(rc, mid + , r, x, y, s[p].id), s[p].id = nid;
else ins(lc, l, mid, x, y, nid);
} chkMin(res(p), min(l1, r1));
up(p);
return;
} if(x <= mid) ins(lc, l, mid, x, y, nid);
if(y > mid) ins(rc, mid + , r, x, y, nid);
up(p);
} ll query(int p, int l, int r, int x, int y) {
if(x <= l && y >= r) return res(p);
ll res = Val0;
if(s[p].id) {
ll ld = dis[pos[max(l, x)]], rd = dis[pos[min(y, r)]];
chkMin(res, min(ld * kk[s[p].id], rd * kk[s[p].id]) + bb[s[p].id]);
}
if(x <= mid) chkMin(res, query(lc, l, mid, x, y));
if(y > mid) chkMin(res, query(rc, mid + , r, x, y));
return res;
} } using namespace SegT; inline void solve(int x, int y) {
ll res = Val0;
for(; top[x] != top[y]; ) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
chkMin(res, query(, , n, id[top[x]], id[x]));
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
chkMin(res, query(, , n, id[x], id[y]));
printf("%lld\n", res);
} inline void addSeg(int x, int y, int nid) {
for(; top[x] != top[y]; ) {
// if(dep[top[x]] < dep[top[y]]) swap(x, y);
ins(, , n, id[top[x]], id[x], nid);
x = fa[top[x]];
}
// if(dep[x] > dep[y]) swap(x, y);
ins(, , n, id[y], id[x], nid);
} int main() {
read(n), read(qn);
for(int i = ; i < n; i++) {
int x, y; ll v;
read(x), read(y), read(v);
add(x, y, v), add(y, x, v);
} dfs1(, , , 0LL), dfs2(, ); /* for(int i = 1; i <= n; i++)
printf("%lld ", dis[pos[i]]);
printf("\n"); */ build(, , n);
bb[] = Val0, kk[] = 0LL;
for(int op, x, y, cnt = ; qn--; ) {
read(op), read(x), read(y);
if(op == ) {
ll k, b;
read(k), read(b); int z = getLca(x, y);
++cnt;
kk[cnt] = -k, bb[cnt] = b + dis[x] * k;
addSeg(x, z, cnt); ++cnt;
kk[cnt] = k, bb[cnt] = b + (dis[x] - 2LL * dis[z]) * k;
addSeg(y, z, cnt);
} else solve(x, y);
} return ;
}

Luogu 4069 [SDOI2016]游戏的更多相关文章

  1. 【题解】Luogu P4069 [SDOI2016]游戏

    原题传送门 看到这种题,想都不用想,先写一个树链剖分 然后发现修改操作增加的是等差数列,这使我们想到了李超线段树 先进性树剖,然后用李超线段树维护区间最小,这样就做完了(写码很容易出错) 复杂度为\( ...

  2. 4515: [Sdoi2016]游戏

    4515: [Sdoi2016]游戏 链接 分析: 树链剖分 + 超哥线段树.注意细节. 代码: #include<cstdio> #include<algorithm> #i ...

  3. 【BZOJ4515】[Sdoi2016]游戏 树链剖分+线段树

    [BZOJ4515][Sdoi2016]游戏 Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 1234567 ...

  4. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  5. [Luogu P3825] [NOI2017] 游戏 (2-SAT)

    [Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...

  6. BZOJ4515: [Sdoi2016]游戏

    Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...

  7. bzoj 4515: [Sdoi2016]游戏

    Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...

  8. [SDOI2016]游戏

    Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...

  9. Luogu P4705 玩游戏

    题目描述 Alice 和 Bob 又在玩游戏. 对于一次游戏,首先 Alice 获得一个长度为 ​ 的序列 ​,Bob 获得一个长度为 ​ 的序列 bb.之后他们各从自己的序列里随机取出一个数,分别设 ...

随机推荐

  1. 解决----Word无法创建工作文件,请检查临时环境变量

    用户在运行Word2003或打开Word2003文档时,可能会出现“Word无法创建工作文件,请检查临时环境变量”的错误提示,此问题主要是由于Word2003的用户设置出现损坏而造成的.网上针对此问题 ...

  2. numpy之通用函数ufunc

    通用函数-元素级数组函数 通用函数(ufunc)是一种对ndarray执行元素级运算的函数. 一元ufunc import numpy as np arr = np.arange(-10,10,2) ...

  3. XMemcached使用经历

    XMemcached就是Memcached的java客户端之一,目前项目里用到了.据说它比起其他的java客户端从性能上要好一点,实现方式是NIO的.先看怎么实例化出来一个Memcached客户端吧: ...

  4. Erlang基础 -- 介绍 -- 历史及Erlang并发

    前言 最近在总结一些Erlang编程语言的基础知识,拟系统的介绍Erlang编程语言,从基础到进阶,然后再做Erlang编程语言有意思的库的分析. 其实,还是希望越来越多的人关注Erlang,使用Er ...

  5. Java-Runoob:Java 变量类型

    ylbtech-Java-Runoob:Java 变量类型 1.返回顶部 1. Java 变量类型 在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下: type identifie ...

  6. 1116 Come on! Let's C

    题意:略. 思路:略. 代码: #include <cstdio> #include <cmath> ; }; bool isPrime(int n) { ) return f ...

  7. thinkphp中的volist标签

    属性: name(必须):要输出的数据模板变量 id(必须):循环变量 offset(可选):要输出数据的offset length(可选):输出数据的长度 key(可选):循环的key变量,默认值为 ...

  8. activemq安装运行及其在springboot中的queue和topic使用

    安装activemq 运行 springboot使用 依赖 配置 Producer Consumer ComsumerTopic 使用 安装activemq http://activemq.apach ...

  9. VMware虚拟机安装Centos7详细步骤过程(图文)[转载]

    Centos7官网下载地址:https://www.centos.org/download/ 图文安装步骤转载地址: https://www.jianshu.com/p/ce08cdbc4ddb?ut ...

  10. CSS——优先级

    转自:http://www.planabc.net/2008/05/06/css_specificity/ CSS2.1 中规定了关于 CSS 规则 Specificity(特异性)的计算方式,用一个 ...