Time:2016.05.10
Author:xiaoyimi
转载注明出处谢谢


传送门
思路:
李超线段树
一开始听faebdc讲,并没有听的很懂ww
后来找到良心博文啊有木有
折越

首先可以把修改转换一下,因为那个dis非常不爽。显然s~t的路径有s~lca和lca~t组成。令d[x]表示x的深度,对于s~lca上面的点,修改的值相当于a*(d[s]-d[x])+b=-a*d[x]+(b-a*d[s]),lca~t上面的点的值相当于a*(d[s]+d[x]-2*d[lca])+b=a*d[x]+(b+a*(d[s]-d[x]*2)),这样就可以得到新的a’和b’,然后一个点的值就相当于a’*d[x]+b’了,这样就只和a’,b’和d[x]有关了。
注意到在树链剖分对应的线段树区间中,相连的一部分它们在树种也是相连的,这样就满足d[]单调递增,观察a’*d[x]+b’,发现这相当于直线f(x)=a’x+b在d[x](两个x不是一个意思)处的取值!那么就相当于用线段树维护一个区间中的若干条直线在每个部分的最小值。
不妨考虑标记永久化(这里只是一定程度上的永久化但还是要下传的)。让线段树中的一个节点只对应一条直线,那么如果在这个区间加入一条直线怎么办呢?要分类讨论,设新加入的f1(x)=k1x+b1,原来的f2(x)=k2x+b2,左端点为l,右端点为r,那么有:
1.f1(d[l])<f2(d[l])且f1(d[r])<f2(d[r]),对应一条直线在两个端点都比另一条小,那么显然在l~r中f1(x)处处比f2(x)小,直接把f2(x)替换为f1(x);
2.同理若上式的两个符号都为>,那么f1(x)处处不如f2(x)优,不做更改。
3.k1<k2,那么由于不满足1.2,显然两条直线有交点,此时解不等式f1(x)<f2(x)得到x>(b1-b2)/(k2-k1),那么判断(b1-b2)/(k2-k1)在左半区间还是右半区间递归下传即可;
4.k1>k2同理。

注意:
1.会有除0的情况,所以把f1=f2的情况归到不等的情况里去判断,不然会RE出翔
2.对于交点的判断是对于dis[mid]的比较,而不是线段树区间mid的比较!
3.标记永久化感觉很玄妙啊,处理时要小心!
代码:

#include<bits/stdc++.h>
#define M 100003
#define inf 123456789123456789LL
#define LL long long
using namespace std;
int n,m,tot,cnt;
int dep[M],siz[M],son[M],top[M],pre[M],L[M],fa[M],first[M];
LL dis[M];
struct edge
{int u,v,w,next;
}e[M<<1];
struct Segment_tree
{bool lazy;LL minn,k,b;
}tree[M<<2];
int in()
{char ch=getchar();int t=0,f=1;while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)) t=(t<<3)+(t<<1)+ch-48,ch=getchar();return f*t;
}
void add(int x,int y,int z) {e[++tot]=(edge){x,y,z,first[x]};first[x]=tot;}
LL cal(int x,LL k,LL b){return dis[x]*k+b;}
void dfs1(int x)
{siz[x]=1;for (int i=first[x];i;i=e[i].next)if (e[i].v!=fa[x])dep[e[i].v]=dep[x]+1,fa[e[i].v]=x,dis[e[i].v]=dis[x]+e[i].w,dfs1(e[i].v),siz[x]+=siz[e[i].v],son[x]=(siz[e[i].v]>siz[son[x]]?e[i].v:son[x]);
}
void dfs2(int x,int tp)
{top[x]=tp;L[x]=++cnt;pre[cnt]=x;if (son[x]) dfs2(son[x],tp);for (int i=first[x];i;i=e[i].next)if (son[x]!=e[i].v&&fa[x]!=e[i].v) dfs2(e[i].v,e[i].v);
}
int LCA(int x,int y)
{int f1=top[x],f2=top[y];while (f1!=f2){if (dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);x=fa[f1];f1=top[x];}return dep[x]>dep[y]?y:x;
}
void build(int rt,int begin,int end)
{tree[rt].minn=inf;if (begin==end) return;int mid=begin+end>>1;build(rt<<1,begin,mid);build(rt<<1|1,mid+1,end);
}
void pushup(int rt,int begin,int end)
{if (begin==end) tree[rt].minn=inf;else tree[rt].minn=min(tree[rt<<1].minn,tree[rt<<1|1].minn);if (tree[rt].lazy)tree[rt].minn=min(tree[rt].minn,min(tree[rt].k*dis[pre[begin]],tree[rt].k*dis[pre[end]])+tree[rt].b);
}
void update(int rt,int begin,int end,int l,int r,LL k,LL b)
{int mid=begin+end>>1;if (l<=begin&&end<=r)if (!tree[rt].lazy){tree[rt].lazy=1;tree[rt].k=k;tree[rt].b=b;pushup(rt,begin,end);return;}else{LL f1=cal(pre[begin],tree[rt].k,tree[rt].b),f2=cal(pre[end],tree[rt].k,tree[rt].b),f3=cal(pre[begin],k,b),f4=cal(pre[end],k,b);if (f1>f3&&f2>f4)tree[rt].k=k,tree[rt].b=b;else if (f1<=f3&&f2<=f4) return;else{LL p=(b-tree[rt].b)/(tree[rt].k-k);if (tree[rt].k>k){if (p<=dis[pre[mid]])swap(tree[rt].k,k),swap(tree[rt].b,b),update(rt<<1,begin,mid,l,r,k,b);elseupdate(rt<<1|1,mid+1,end,l,r,k,b);}else{if (p>dis[pre[mid]])swap(tree[rt].k,k),swap(tree[rt].b,b),update(rt<<1|1,mid+1,end,l,r,k,b);elseupdate(rt<<1,begin,mid,l,r,k,b);}}pushup(rt,begin,end);return;}if (mid>=l) update(rt<<1,begin,mid,l,r,k,b);if (mid<r)  update(rt<<1|1,mid+1,end,l,r,k,b);pushup(rt,begin,end);
}
LL get(int rt,int begin,int end,int l,int r)
{if (l<=begin&&end<=r) return tree[rt].minn;int mid=(begin+end)>>1;LL ans=inf; if (tree[rt].lazy)ans=min(ans,tree[rt].b+min(dis[pre[max(l,begin)]]*tree[rt].k,dis[pre[min(r,end)]]*tree[rt].k));if (mid>=l) ans=min(ans,get(rt<<1,begin,mid,l,r));if (mid<r)  ans=min(ans,get(rt<<1|1,mid+1,end,l,r));return ans;
}
void solve(int x,int y)
{LL ans=inf;int f1=top[x],f2=top[y];while (f1!=f2){if (dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);ans=min(ans,get(1,1,n,L[f1],L[x]));x=fa[f1];f1=top[x];}if (dep[x]>dep[y]) swap(x,y);ans=min(ans,get(1,1,n,L[x],L[y]));printf("%lld\n",ans);
}
main()
{n=in();m=in();int opt,x,y,z,s,t;for (int i=1;i<n;i++)x=in(),y=in(),z=in(),add(x,y,z),add(y,x,z);dfs1(1);dfs2(1,1);build(1,1,n); for (int i=1;i<=m;i++){opt=in();s=in();t=in();if (opt==1){x=in();y=in();int lca=LCA(s,t);LL  k1=-x,b1=dis[s]*x+y,k2=x,b2=dis[s]*x-dis[lca]*x*2+y;for (;top[s]!=top[lca];s=fa[top[s]])update(1,1,n,L[top[s]],L[s],k1,b1);update(1,1,n,L[lca],L[s],k1,b1);for (;top[t]!=top[lca];t=fa[top[t]])update(1,1,n,L[top[t]],L[t],k2,b2);update(1,1,n,L[lca],L[t],k2,b2);}elsesolve(s,t);}
}

【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)相关推荐

  1. 兰州大学第一届 飞马杯 ★★快乐苹果树★★ 树链剖分 + 懒标记 + 树状数组

    传送门 文章目录 题意: 思路: 题意: 思路: 第一次听说树链剖分能在fa[top[i]]fa[top[i]]fa[top[i]]的地方加懒标记,学到了学到了. 首先不能被题目吓住,这个题目仔细剖析 ...

  2. #6073. 「2017 山东一轮集训 Day5」距离(树链剖分 + 永久标记主席树)

    #6073. 「2017 山东一轮集训 Day5」距离 给定一颗有nnn个节点带边权的树,以及一个排列ppp,path(u,v)path(u, v)path(u,v)为u,vu, vu,v路径上的点集 ...

  3. 洛谷3384(树链剖分模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  4. CF1137F Matches Are Not a Child‘s Play(树上数据结构问题、树链剖分+ODT)

    Description 一棵 n 个点的树,点权最初为 1 ∼ n 的排列. 定义一个删点过程:每次找到权值最小的叶子,删去它以及连接的边,重复这个过程直到剩下一个点,然后删去最后的点. 处理 q 个 ...

  5. BZOJ 3083: 遥远的国度(树链剖分+DFS序)

    可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...

  6. NOI2015 Day1 T2 软件包管理器 树链剖分

    NKOJ3423 NOI2015 软件包管理器 时间限制 : 20000 MS 空间限制 : 524288 KB 问题描述 Linux用户和OS X用户一定对软件包管理器不会陌生.通过软件包管理器,你 ...

  7. 【树链剖分】LCA(P4211)

    正题 P4211 题目大意 给你一棵树,有m次询问,每次询问要回答∑i=lrdep[lca(x,i)]\sum_{i=l}^rdep[lca(x,i)]∑i=lr​dep[lca(x,i)] 解题思路 ...

  8. POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

    题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每 ...

  9. [ZJOI2015] 幻想乡战略游戏(树链剖分 + 线段树二分 + 带权重心)

    problem luogu-P3345 solution 这是一个带权重心的题,考察动态点分治.点分治?呵,不可能的,这辈子都不可能写点分治 我们重新考虑重心的性质:以这个点为根时,所有子树的大小不会 ...

最新文章

  1. hdu1285 拓扑排序+优先队列
  2. 阿里研究员谷朴:警惕软件复杂度困局
  3. 苹果欲借免费纳米SIM卡技术控制行业标准
  4. 常见的加密和解密算法—MD5
  5. ECCV 2018 StructSiam:《Structured Siamese Network for Real-Time Visual Tracking》论文笔记
  6. 添加第三方库到Maven资源库
  7. python命令行输入参数_Python3.x那些事儿:[3]命令行参数传递
  8. MongoDB投影字段
  9. C++默认构造函数的合成
  10. 【渝粤教育】电大中专电商运营实操 (17)作业 题库
  11. 云计算之路:数据库服务器的选择——舍RDS取云服务器
  12. the road to TCPIP(1)--TCPIP详解--数据链路层
  13. 手机怎么更改ip地址
  14. GCN与图谱理论(三):图的谱分析与图傅里叶变换
  15. Uva 11584 - Partitioning by Palindromes(预处理+DP)
  16. 浙江大学计算机科学与技术学院工业设计,浙江大学工业设计专业
  17. php中trim 的作用,PHP trim()函数的作用和使用方法
  18. 数字信号处理基于计算机的方法答案,数字信号处理—基于计算机的方法第4章答案.pdf...
  19. 操作系统之生产者与消费者
  20. PMP备考错题集-模拟三

热门文章

  1. r语言msar如何用_如何在jupyter notebook中使用R语言
  2. PDE双曲型方程数值解形式及例题分析
  3. WORD限制别人只能填写窗体而不能修改文档其他内容?
  4. python图像卷积_图像处理——卷积原理、二维卷积python实现
  5. xp电脑主题包_怎么让手机变电脑?一个APP让你的安卓手机变Windows电脑
  6. Spark优化一则 - 减少Shuffle
  7. c# task添加顺序_关于c#:Task和async等待所需的指导
  8. python多行语句_python多行语句
  9. java设置按钮调用问题_按钮相关问题:尝试在空对象引用上调用虚方法
  10. rpc 服务器不可用_什么是远程过程调用RPC