【LOJ】#2032. 「SDOI2016」游戏
题解
看错题了,以为单次修改相当于一个覆盖,后来才明白“添加”……
就相当于添加很多线段求最小值
首先这个等差数列添加的方式比较烦人,我们拆开两条链,一条s到lca,一条lca到t
那么s到lca上的点x值就是\(-A * dis[x] + A * dis[s] + B\)
lca到t上的点x值就是\(A * dis[x] + A * (dis[s] - 2 * dis[lca]) +B\)
这个时候就是点值代入的一次函数的形式,考虑怎么插入一条线段
这个线段树上的节点原来维护着一条直线,如果新加入的线段两端都小于原来线段,那么原来线段就替换掉
如果两端都大于,那么这条线段没用,退出
如果有交点,那么求出交点的位置,下取整,保留靠下的长度较长的一条线段,另一条线段根据交点的位置分到左右区间递归处理
听说叫什么李超线段树。。。
用可持久化处理区间最大值,每次询问的时候查询区间在当前节点的线段能取到的最小值
加上树链剖分,复杂度是\(O(n \log^3 n)\)
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M;
struct Line {
int64 A,B;
Line(int64 _A = 0,int64 _B = 0){A = _A;B = _B;}
int64 cal(int64 x) {return A * x + B;}
};
struct node {
int to,next;
int64 val;
}E[MAXN * 2];
struct Tr_node {
int L,R;
Line f;int64 val;
bool cover;
}tr[MAXN * 4];
int sumE,head[MAXN];
int64 dis[MAXN];
int fa[MAXN],dep[MAXN],siz[MAXN],son[MAXN],top[MAXN],dfn[MAXN],idx,id[MAXN];
void build(int u,int l,int r) {
tr[u].L = l;tr[u].R = r;
tr[u].cover = 0;tr[u].val = 123456789123456789LL;
if(l == r) return;
int mid = (l + r) >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
}
int64 down(int64 A,int64 B) {
if(B < 0) A = -A,B = -B;
int64 C = A / B;
return C - (C * B > A);
}
int64 cross(Line f,Line g) {
return down(f.B - g.B,g.A - f.A);
}
void Add_Line(int u,Line g) {
int64 l = dis[id[tr[u].L]],r = dis[id[tr[u].R]];
tr[u].val = min(tr[u].val,min(g.cal(l),g.cal(r)));
if(!tr[u].cover) {tr[u].f = g;tr[u].cover = 1;return;}
else {
int64 mid = (tr[u].L + tr[u].R) >> 1;
mid = dis[id[mid]];
if(tr[u].f.cal(l) >= g.cal(l) && tr[u].f.cal(r) >= g.cal(r)) {
tr[u].f = g;return;
}
else if(tr[u].f.cal(l) <= g.cal(l) && tr[u].f.cal(r) <= g.cal(r)) return;
else if(tr[u].f.cal(l) <= g.cal(l)) {
if(cross(tr[u].f,g) <= mid) {Add_Line(u << 1,tr[u].f);tr[u].f = g;}
else Add_Line(u << 1 | 1,g);
}
else {
if(cross(tr[u].f,g) <= mid) {Add_Line(u << 1,g);}
else {Add_Line(u << 1 | 1,tr[u].f);tr[u].f = g;}
}
}
}
void Modify(int u,int l,int r,Line g) {
tr[u].val = min(tr[u].val,min(g.cal(dis[id[l]]),g.cal(dis[id[r]])));
if(tr[u].L == l && tr[u].R == r) {
Add_Line(u,g);
return ;
}
int mid = (tr[u].L + tr[u].R) >> 1;
if(r <= mid) Modify(u << 1,l,r,g);
else if(l > mid) Modify(u << 1 | 1,l,r,g);
else {Modify(u << 1,l,mid,g);Modify(u << 1 | 1,mid + 1,r,g);}
}
int64 Query(int u,int l,int r) {
int64 res = 123456789123456789LL;
if(tr[u].cover) {
res = min(res,tr[u].f.cal(dis[id[l]]));
res = min(res,tr[u].f.cal(dis[id[r]]));
}
if(tr[u].L == l && tr[u].R == r) {
res = min(res,tr[u].val);
return res;
}
int mid = (tr[u].L + tr[u].R) >> 1;
if(r <= mid) res = min(res,Query(u << 1,l,r));
else if(l > mid) res = min(res,Query(u << 1 | 1,l,r));
else {
res = min(res,Query(u << 1,l,mid));
res = min(res,Query(u << 1 | 1,mid + 1,r));
}
return res;
}
void Modify_Path(int s,int t,int64 A,int64 B) {
while(top[s] != top[t]) {
if(dep[top[s]] < dep[top[t]]) swap(s,t);
Modify(1,dfn[top[s]],dfn[s],Line(A,B));
s = fa[top[s]];
}
if(dep[s] > dep[t]) swap(s,t);
Modify(1,dfn[s],dfn[t],Line(A,B));
}
int64 Query_Path(int s,int t) {
int64 res = 123456789123456789LL;
while(top[s] != top[t]) {
if(dep[top[s]] < dep[top[t]]) swap(s,t);
res = min(res,Query(1,dfn[top[s]],dfn[s]));
s = fa[top[s]];
}
if(dep[s] > dep[t]) swap(s,t);
res = min(res,Query(1,dfn[s],dfn[t]));
return res;
}
void add(int u,int v,int64 c) {
E[++sumE].to = v;
E[sumE].next = head[u];
E[sumE].val = c;
head[u] = sumE;
}
void dfs1(int u) {
dep[u] = dep[fa[u]] + 1;
siz[u] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
fa[v] = u;
dis[v] = dis[u] + E[i].val;
dfs1(v);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
return;
}
void dfs2(int u) {
dfn[u] = ++idx;
id[idx] = u;
if(!top[u]) top[u] = u;
if(son[u]) {
top[son[u]] = top[u];
dfs2(son[u]);
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u] && v != son[u]) dfs2(v);
}
}
int find_lca(int a,int b) {
while(top[a] != top[b]) {
if(dep[top[a]] < dep[top[b]]) swap(a,b);
a = fa[top[a]];
}
return dep[a] < dep[b] ? a : b;
}
void Init() {
read(N);read(M);
int u,v;int64 w;
for(int i = 1 ; i < N ; ++i) {
read(u);read(v);read(w);
add(u,v,w);add(v,u,w);
}
dfs1(1);dfs2(1);
build(1,1,N);
}
void Solve() {
int op,s,t;
int64 A,B;
while(M--) {
read(op);read(s);read(t);
if(op == 1) {
read(A);read(B);
int f = find_lca(s,t);
Modify_Path(s,f,-A,A * dis[s] + B);
Modify_Path(f,t,A,A * (dis[s] - 2 * dis[f]) + B);
}
else {
out(Query_Path(s,t));enter;
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}
昨天真是奇颓无比
三体真好看
【LOJ】#2032. 「SDOI2016」游戏的更多相关文章
- [LOJ 2070] 「SDOI2016」平凡的骰子
[LOJ 2070] 「SDOI2016」平凡的骰子 [题目链接] 链接 [题解] 原题求的是球面面积 可以理解为首先求多面体重心,然后算球面多边形的面积 求重心需要将多面体进行四面体剖分,从而计算出 ...
- loj #2305. 「NOI2017」游戏
#2305. 「NOI2017」游戏 题目描述 小 L 计划进行 nnn 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏. 小 L 的赛车有三辆,分别用大写字母 AAA.BBB. ...
- loj#2305. 「NOI2017」游戏 2-sat
链接 https://loj.ac/problem/2305 https://www.luogu.org/problemnew/show/P3825 思路 3-sat神马的就不要想了,NP问题 除去x ...
- LOJ#2070. 「SDOI2016」平凡的骰子(计算几何)
题面 传送门 做一道题学一堆东西不管什么时候都是美好的体验呢-- 前置芝士 混合积 对于三个三维向量\(a,b,c\),定义它们的混合积为\((a\times b)\cdot c\),其中$\time ...
- loj2032 「SDOI2016」游戏
做了 [JSOI2008]Blue Mary开公司 以后发现这 tm 不就是个傻逼树剖+李超线段树吗,做了以后发现我才是傻逼--树剖竟然写错了--这题是我目前写过最长的代码了qwq #include ...
- LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)
题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
- Loj #3044. 「ZJOI2019」Minimax 搜索
Loj #3044. 「ZJOI2019」Minimax 搜索 题目描述 九条可怜是一个喜欢玩游戏的女孩子.为了增强自己的游戏水平,她想要用理论的武器武装自己.这道题和著名的 Minimax 搜索有关 ...
- LOJ_2305_「NOI2017」游戏 _2-sat
LOJ_2305_「NOI2017」游戏 _2-sat 题意: 给你一个长度为n的字符串S,其中第i个字符为a表示第i个地图只能用B,C两种赛车,为b表示第i个地图只能用A,C两种赛车,为c表示第i个 ...
随机推荐
- [应用篇]第三篇 JSP 标准标签库(JSTL)总结
有一种友谊叫做: "陪我去小卖部." "不去," "我请你" "走." 你想起了谁:胖先生?还有人陪你吗? JSP 标准 ...
- kibana做图表无法选取需要选的字段
kibana做图表无法选取需要选的字段,即通过term的方式过滤选择某一个field时发现列表里无此选项. 再去discover里看,发现此字段前面带有问号,点击后提示这个字段未做索引,不能用于vis ...
- 【记录】css样式
记录css的样式设置,方便以后使用. 1.绝对定位,自适应父级大小css: .search-icon-delete { background: url('../../assets/images/sea ...
- 另类之将ipython notebook嵌入blog方法
另类之将ipython notebook嵌入blog方法 ipynb文件很强大. 可是一直苦于没有找到好的方法把它直接嵌入到博文里. 现在得到一个另类的方法: 就是利用github集成了nbviewe ...
- UNIX环境高级编程 第13章 守护进程
守护进程daemon是一种生存周期很长的进程.它们通常在系统引导时启动,在系统关闭时终止.守护进程是没有终端的,它们一直在后台运行. 守护进程的特征 在Linux系统中,可以通过命令 ps -efj ...
- 20155303 《Java程序设计》实验一(Java开发环境的熟悉)实验报告
20155303 <Java程序设计>实验一(Java开发环境的熟悉)实验报告 一.实验内容及步骤 (一)使用JDK编译.运行简单的java程序 命令行下的程序开发 步骤一(新建文件夹): ...
- 【比赛游记】THUSC2018酱油记
day -1 早上4:30就要起来去飞机场…… 7点的飞机,10:30就到北京了. 北京的街景并没有我想像的漂亮……大概是因为我在四环外〒▽〒 晚上还有CF div3场,果断的去水了,因为太累就没有打 ...
- 【洛谷】P1445 没占到1444的愤怒
继续洛谷刷水日常,突然遇到一道不是很水的题目…… https://www.luogu.org/problem/show?pid=1445 题意:给定n(1<=n<=1000000),求方程 ...
- 空洞卷积(dilated Convolution) 与感受野(Receptive Field)
一.空洞卷积 空洞卷积是是为了解决基于FCN思想的语义分割中,输出图像的size要求和输入图像的size一致而需要upsample,但由于FCN中使用pooling操作来增大感受野同时降低分辨率,导致 ...
- 正则表达式基础->
描述:(grep) 正则表达式是一种字符模式,用于在查找过程中匹配指定的字符.在大多数程序里,正则表达式都被置于两个正斜杠之间,它匹配被查找的行中任何位置出现的相同模式 基础正则表达式 正则表达式 描 ...