题意:给定一张图,保证 $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. Python 数据结构理解分享

    摘要:分享学习Python数据结构的一些理解,主要包含序列(如列表和元组),映射(如字典)以及集合3中基本的数据结构,以及可变和不可变数据类型. Python 中的数据结构是根据某种方式将数据元素组合 ...

  2. Django REST framework 基本组件

    一.序列化组件 简单使用 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式.我们可以通过声明与Django forms ...

  3. AVR单片机教程——序言

    我一直觉得现在的网络环境对电子技术的学习有一点问题,但始终无法确切地指出,更何况网络上相关资源已经那么丰富. 但我觉得是问题的,无论它到底是不是问题,对我来说总归是一个问题.我学习也不算深入,很多东西 ...

  4. try except 异常捕获的方法、断言的使用

    except as e中的'e'的作用总结 - 2puT - CSDN博客 Python使用try except处理程序异常的三种常用方法分析 Python3和Python2 异常处理except的不 ...

  5. 微信小程序的页面跳转==编程式导航传参 和 标签的方法传参==以及如何过去传递过来的参数

    小程序导航传参接收传递过来的参数 在onload中 实例

  6. SQL case when 遇到null值

    case  when f.FPH is  NULL then a.HSJE else f.KPHSJE  end    yes case f.FPH  when   NULL then a.HSJE ...

  7. dll库生成和使用

    抄自http://www.cnblogs.com/fangyukuan/archive/2010/06/20/1761464.html 1. VS2010中新建Win32-Win32项目,输入名称Dl ...

  8. Visual Studio中找不到.Net Core SDK

    在win 7 64位上安装了.Net Core 2.1 x86 SDK后,又卸载重新安装了.Net Core 3/2 x64 SDK.结果在VS中新建项目时没有.Net Core 3.1 SDK. 在 ...

  9. 读取经纬度坐标并存储为字典格式,即key为ID,value为轨迹点

    示例数据: #格式为txt文本 ID,L,B 001,116.5154,45.1154 001,116.5160,45.1153 ... 002,xxx,xxx ... 目标:建立轨迹数据结构,即di ...

  10. Django中ORM多对多表的操作

    自己创建第三张表建立多对多关系 表的创建 # 老师表和学生表可以是一个多对多的关系,建表时可以手动建立第三张表建立关联 class Student(models.Model): name = mode ...