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.之后他们各从自己的序列里随机取出一个数,分别设 ...
随机推荐
- wifi文件传输
步骤: 1.下载CocoaHTTPServer 2.解压后,将CocoaHTTPServer-master目录下的Core导入工程. 3.打开Samples/SimpleFileUploadServe ...
- FastAdmin 学习线路 (2018-09-09 增加 Layer 组件)
FastAdmin 学习线路 (2018-09-09 增加 Layer 组件) 基础 HTML CSS DIV Javascript 基础 jQuery php 基础 对象 命名空间 Apache 或 ...
- gen already exists but is not a source folder
遇到android项目导入出现后重复空包等错误,往往是导入的java编译级别有关,点击项目properties-> java Compiler ->修改Compiler complianc ...
- 转载:解决eclipse导出javadoc时的“错误: 编码GBK的不可映射字符”问题
转自:http://blog.csdn.net/psy1100/article/details/51179342 今天要将自己的API接口和MODEL导出来一份java doc参考文档, 但是在导出的 ...
- git 基本操作 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013744142037508cf42e51debf49668810645e02887691000
1.创建版本库 (即仓库 repository)简单理解为一个目录,这个目录里的所有文件都可以被git管理起来,每个文件的修改删除,git都能跟踪,一边任何时刻都可以追踪历史,或者在将来某个时刻可以 ...
- easyui tree 加载展开全部节点
$(function () { $('#tbClientListCont').tree({ checkbox: false, url: '/ashx/Client/tbClientList.ashx? ...
- 1139 First Contact
题意:给出n个人,m对朋友关系,其中带负号的表示女孩.然后给出k对查询a,b,要求找出所有a的同性别好友c,以及b的同性别好友d,且c和d又是好友关系.输出所有满足条件的c和d,按c的升序输出,若c编 ...
- (转)Docker - 创建 Docker overlay network (containers 通信)
原文链接: http://www.cnblogs.com/AlanWalkOn/p/6101875.html --- 创建基于Key-Value的Docker overlay network. 这样运 ...
- VirtualBox 桥接
1.设置Virtual box,取消DHCP服务 管理->全局设定->网络->Host-Only->网络明细->DHCP服务器->启用服务器选项取消 2.宿机设置 ...
- python学习——练习题(3)
""" 题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少? """ import math d ...