Luogu 4069 [SDOI2016]游戏
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]游戏的更多相关文章
- 【题解】Luogu P4069 [SDOI2016]游戏
原题传送门 看到这种题,想都不用想,先写一个树链剖分 然后发现修改操作增加的是等差数列,这使我们想到了李超线段树 先进性树剖,然后用李超线段树维护区间最小,这样就做完了(写码很容易出错) 复杂度为\( ...
- 4515: [Sdoi2016]游戏
4515: [Sdoi2016]游戏 链接 分析: 树链剖分 + 超哥线段树.注意细节. 代码: #include<cstdio> #include<algorithm> #i ...
- 【BZOJ4515】[Sdoi2016]游戏 树链剖分+线段树
[BZOJ4515][Sdoi2016]游戏 Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 1234567 ...
- [luogu]P1070 道路游戏[DP]
[luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...
- [Luogu P3825] [NOI2017] 游戏 (2-SAT)
[Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...
- BZOJ4515: [Sdoi2016]游戏
Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...
- bzoj 4515: [Sdoi2016]游戏
Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...
- [SDOI2016]游戏
Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...
- Luogu P4705 玩游戏
题目描述 Alice 和 Bob 又在玩游戏. 对于一次游戏,首先 Alice 获得一个长度为 的序列 ,Bob 获得一个长度为 的序列 bb.之后他们各从自己的序列里随机取出一个数,分别设 ...
随机推荐
- UIImage+PYJAnimatedGIF
UIImage+PYJAnimatedGIF.h: #import <UIKit/UIKit.h> @interface UIImage (PYJAnimatedGIF) + (UIIma ...
- LeetCode Replace Words
原题链接在这里:https://leetcode.com/problems/replace-words/description/ 题目: In English, we have a concept c ...
- JavaScript 与 Java、PHP 的比较
网站开发的实践从设计方面开始,包括客户端编程语言.大体上说,在网页设计中使用了三种语言:HTML,CSS和Java.自从网站发明以来,HTML和CSS已经成为网页设计的基础,但是Java被用于添加网站 ...
- LG3374 【模板】树状数组 1
题意 如题,已知一个数列,你需要进行下面两种操作: 将某一个数加上x 求出某区间每一个数的和 对于100%的数据:N<=500000,M<=500000 分析 cdq分治解决,参照mlys ...
- 笔记:LIR2032 电池充电记录
笔记:LIR2032 电池充电记录 LIR2032 电池是锂电池,形状和 CR2032 一样,只不过可以充电,材料是锂离子. 一个单颗的 LIR2032 电池容量只有 40mAH,容量很小. 那么就需 ...
- 并发问题 关于Redis
并发问题 关于Redis [吐槽]Jimesembria 付费请人解这个BUG , 有没有php同学有兴趣,(问题原因是理论上是5分钟内不生产同样金额的订单, 但是由于并发原因没控制好) 10:34: ...
- laravel 网站速率优化
https://segmentfault.com/a/1190000009954966
- IaaS vs PaaS vs SaaS
在云计算的早期阶段,企业面临的最大问题是他们是否应该使用公共云服务.如今,几乎所有的组织都在采用一些公共云服务.更重要的问题是企业应该使用哪种云服务:基础设施即服务(IaaS),平台即服务(PaaS) ...
- 容器中跨主机的网络方案-Weave
容器中的网络是建立docker集群的重要内容. 本文将介绍如何用Weave实现容器的多节点互通. Weave是一个开源的项目,其网站为: https://www.weave.works/ 其工作原理相 ...
- CAN总线优点
废除传统的站地址编码,代之以对通信数据块进行编码,可以多主方式工作: 采用非破坏性仲裁技术,当两个节点同时向网络上传送数据时,优先级低的节点主动停止数据发送,而优先级高的节点可不受影响继续传输数据,有 ...