题意:给定一张图,保证 $1$ 号点到其他所有点的最短路径是唯一的,求:对于点 $i$,不经过 $1$ 到 $i$ 最短路径上最后一条边的最短路.

题解:可以先建出最短路树,然后枚举每一条非树边.

对于一条非树边,影响的只是 $(u,lca)$,$(lca,v)$ 这些点的答案,然后你发现可以写成 $dep[a]-dep[u]+val[i]+dep[v]$

对于 $a$ 来说,第一项是固定的,后面的几项对于一个链来说都是相同的,所以直接用 $LCT$ 维护区间最小值就行了.

#include <bits/stdc++.h>
#define N 100003
#define M 200005
#define ll long long
#define inf 1000000000000
#define inf2 10000000000
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
using namespace std;
ll output[N];
vector<int>G[N];
int lst[N],from[N],n,m;
namespace Dij
{
ll val[M<<1],d[N];
int hd[N],to[M<<1],nex[M<<1],done[N],edges,s;
struct Node
{
int u;
ll dis;
Node(int u=0,ll dis=0):u(u),dis(dis){}
bool operator<(Node b) const { return b.dis<dis; }
};
priority_queue<Node>q;
void addedge(int u,int v,ll c)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void dijkstra()
{
memset(d,0x3f,sizeof(d));
d[s]=0ll;
q.push(Node(s,0ll));
while(!q.empty())
{
Node e=q.top(); q.pop();
int u=e.u;
if(done[u]) continue;
done[u]=1;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(d[u]+val[i]<d[v])
{
lst[v]=i;
from[v]=u;
d[v]=d[u]+val[i];
q.push(Node(v, d[v]));
}
}
}
for(int i=2;i<=n;++i) G[from[i]].push_back(i);
}
}
namespace tree
{
int tim;
int size[N],dfn[N],top[N],dep[N],son[N],fa[N];
void dfs1(int u,int ff)
{
fa[u]=ff,size[u]=1,dep[u]=dep[ff]+1;
for(int i=0;i<G[u].size();++i)
{
dfs1(G[u][i],u);
size[u]+=size[G[u][i]];
if(size[G[u][i]]>size[son[u]]) son[u]=G[u][i];
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(son[u]) dfs2(son[u], tp);
for(int i=0;i<G[u].size();++i)
if(G[u][i]!=son[u]) dfs2(G[u][i], G[u][i]);
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
};
struct Link_Cut_Tree
{
#define lson p[x].ch[0]
#define rson p[x].ch[1]
int sta[N];
struct Node
{
int ch[2],tag,f,rev;
ll minn,pu,val;
}p[N];
inline int get(int x) { return p[p[x].f].ch[1]==x; }
inline int isrt(int x) { return !(p[p[x].f].ch[0]==x||p[p[x].f].ch[1]==x); }
inline void pushup(int x)
{
p[x].minn=p[x].val;
if(lson) p[x].minn=min(p[x].minn, p[lson].minn);
if(rson) p[x].minn=min(p[x].minn, p[rson].minn);
}
void markrev(int x)
{
if(x) swap(lson,rson), p[x].rev^=1;
}
void marktag(int x,ll v)
{
if(x)
{
p[x].val=min(p[x].val,v);
if(!p[x].tag || p[x].pu>v) p[x].pu=v, p[x].tag=1;
pushup(x);
}
}
void pushdown(int x)
{
if(!x) return;
if(p[x].tag)
{
if(lson) marktag(lson, p[x].pu);
if(rson) marktag(rson, p[x].pu);
p[x].tag=0;
}
if(p[x].rev)
{
if(lson) markrev(lson);
if(rson) markrev(rson);
p[x].rev=0;
}
}
inline void rotate(int x)
{
int old=p[x].f, fold=p[old].f, which=get(x);
if(!isrt(old)) p[fold].ch[p[fold].ch[1]==old]=x;
p[old].ch[which]=p[x].ch[which^1], p[p[old].ch[which]].f=old;
p[x].ch[which^1]=old, p[old].f=x, p[x].f=fold;
pushup(old), pushup(x);
}
inline void splay(int x)
{
int u=x,v=0,fa;
for(sta[++v]=u; !isrt(u); u=p[u].f) sta[++v]=p[u].f;
for(;v;--v) pushdown(sta[v]);
for(u=p[u].f;(fa=p[x].f)!=u;rotate(x))
if(p[fa].f!=u)
rotate(get(fa)==get(x)?fa:x);
}
void Access(int x)
{
for(int y=0;x;y=x,x=p[x].f)
splay(x), rson=y, pushup(x);
}
void makeroot(int x)
{
Access(x), splay(x), markrev(x);
}
void split(int x,int y)
{
makeroot(x), Access(y), splay(y);
}
int find(int x)
{
for(pushdown(x); rson ; pushdown(x))
{
x=rson;
}
return x;
}
#undef lson
#undef rson
}lct;
void build_tree(int u,int ff)
{
lct.p[u].f=ff;
lct.p[u].val=inf;
lct.pushup(u);
for(int i=0;i<G[u].size();++i) build_tree(G[u][i], u);
}
int main()
{
// setIO("input");
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
Dij::addedge(u,v,1ll*c);
Dij::addedge(v,u,1ll*c);
}
Dij::s=1;
Dij::dijkstra();
tree::dfs1(1,0);
tree::dfs2(1,1);
build_tree(1,0);
for(i=1;i<=n;++i)
{
for(j=Dij::hd[i];j;j=Dij::nex[j])
{
int v=Dij::to[j];
if(lst[v]==j) continue;
int lca=tree::LCA(i,v);
lct.split(v,lca);
int pp=lct.find(lct.p[lca].ch[0]);
if(pp)
{
lct.split(v, pp);
lct.marktag(pp, Dij::d[v]+Dij::d[i]+Dij::val[j]);
}
}
}
for(i=2;i<=n;++i)
{
lct.Access(i);
lct.splay(i);
if(lct.p[i].val>=inf2) printf("-1\n");
else printf("%lld\n",lct.p[i].val-Dij::d[i]);
}
return 0;
}

  

BZOJ 1576 树剖+LCT的更多相关文章

  1. CF827D Best Edge Weight[最小生成树+树剖/LCT/(可并堆/set启发式合并+倍增)]

    题意:一张图求每条边边权最多改成多少可以让所有MST都包含这条边. 这题还是要考察Kruskal的贪心过程. 先跑一棵MST出来.然后考虑每条边. 如果他是非树边,要让他Kruskal的时候被选入,必 ...

  2. [Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2243 线段树+树链剖分,在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色 ...

  3. [GXOI/GZOI2019]旧词(树上差分+树剖)

    前置芝士:[LNOI2014]LCA 要是这题放HNOI就好了 原题:\(\sum_{l≤i≤r}dep[LCA(i,z)]\) 这题:\(\sum_{i≤r}dep[LCA(i,z)]^k\) 对于 ...

  4. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

  5. [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】

    题目链接: BZOJ - 1576 题目分析 首先Orz Hzwer的题解. 先使用 dijikstra 求出最短路径树. 那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿 ...

  6. 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)

    洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...

  7. bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...

  8. BZOJ2157 旅游 【树剖 或 LCT】

    题目 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径. ...

  9. BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)

    BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度). 两种做法 1 树剖+离线+线段树 这道题求的是一个点zzz与[l,r][l,r][l,r]内所有点的lcalca ...

随机推荐

  1. java之aop使用及自定义注解

    目的: 1.Java注解简介 2.Java元注解(重点) 3.自定义注解 案例一(获取类与方法上的注解值) 案例二(获取类属性上的注解属性值) 案例三(获取参数修饰注解对应的属性值) 4.Aop自定义 ...

  2. MySQL 体系结构及存储引擎

    MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...

  3. 【转载】C#通过IndexOf方法判断某个字符串是否包含在另一个字符串中

    C#开发过程中针对字符串String类型的操作是常见操作,有时候需要判断某个字符串是否包含在另一个字符串,此时可以使用IndexOf方法以及Contain方法来实现此功能,Contain方法返回Tru ...

  4. python day3 int,str,list类型补充

    目录 python day 3 1. int类小知识点 2. str类小知识点 3. list类小知识点 python day 3 (学习资料来自老男孩教育) 2019/10/06 1. int类小知 ...

  5. rem em min-width: 30em 的意思

    30em=30rem=30x16px=480px @media only screen and (min-width:30 em){ }

  6. vue实现组件切换的两种方式

    <!DOCTYPE html> <html> <head> <title>组件的切换</title> <meta charset=&q ...

  7. Vue路由规则中定义参数

    Vue使用routerLinke定义参数的时候  路由规则中不需要更改任何属性. 路由其实就是我们在html中定义的锚点,点击这个连接跳转一个锚点.vue中的路由也是这个原理, 前提是路由必须创建在实 ...

  8. 【异常】Maxwell异常 Exception in thread "main" net.sf.jsqlparser.parser.TokenMgrError: Lexical error at line 1, column 596. Encountered: <EOF> after : ""

    1 详细异常 Exception in thread "main" net.sf.jsqlparser.parser.TokenMgrError: Lexical error at ...

  9. 001——搭建OpenCV实验环境

    开发环境 VS 2017 15.7.6 OpenCV 3.4.1 搭建环境 设置环境变量 创建Win32 空项目 配置属性管理器 测试代码 #include<opencv2/opencv.hpp ...

  10. Python使用xlrd、pandas包从Excel读取数据

    #coding=utf-8 # pip install xlrd import xlrd def read_from_xls(filepath,index_col_list): #filepath:读 ...