题意:给定一张图,保证 $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. gopacket 在 windows 上面遇到的问题

    前阵子有个需求是使用 golang 抓包改包,我用到了 gopacket 这个包,但是出了一些小问题. 我按照网上的方法进行使用 OpenLive 抓包,发现并不行,报错 error open ada ...

  2. ef core数据迁移的一点小感悟

    ef core在针对mysql数据迁移的时候,有些时候没法迁移...有两种情况没法迁移,一种是因为efcore的bug问题导致没法迁移,这个在github上有个问题集,另外一种是对数据表进行较大幅度的 ...

  3. cmake用法及常用命令总结(全)

    CMakeLists.txt 的语法比较简单,由命令.注释和空格组成,其中命令是不区分大小写的.指令是大小写无关的,参数和变量是大小写相关的.但推荐全部使用大写指令.符号 # 后面的内容被认为是注释. ...

  4. Java内存模型之分析volatile

    前篇博客[死磕Java并发]—–深入分析volatile的实现原理 中已经阐述了volatile的特性了: volatile可见性:对一个volatile的读,总可以看到对这个变量最终的写: vola ...

  5. VBA字符串(十二)

    字符串是一个字符序列,可以由字母,数字,特殊字符或全部字符组成. 如果一个变量被包含在双引号""中,则被认为是一个字符串. 语法 variable_name = "thi ...

  6. nginx Proxy Cache 配置

    总结一下 proxy cache 设置的常用指令及使用方法: proxy_cache proxy_cache zone | off 配置一块公用的内存区域的名称,该区域可以存放缓存的索引数据.注意:z ...

  7. Java程序员的自我修养

    一.自我修养路线图 如图,这是笔者所走的路.且不论这路走的对不对,这个过程中行业环境会影响到你,大可不必钻牛角尖.附上这张图的目的是为了说,如果你想成为一个优秀的程序员,那么你一定要有规划.当然,别想 ...

  8. JS如何做2048(详细)

    在做2048之前,我们首先要了解它的游戏规则,以及运行逻辑 首先,来看上半部分 除了标题外还有记录每次获得的分数,以及总分数,还有一个重新开始按钮,这个最大分数会保存下来. 来看页面内容 页面内容由1 ...

  9. STM8 工程模版

    在st官网下载STM8固件库 拷贝固件库到工程目录下 再创建两个目录 user:存放用户文件.自己编写的源文件 project:存放工程文件 拷贝stm8s_conf.h到user目录下 AIR 创建 ...

  10. SecureCRT和SecureFX的安装和破解

    1.SecureCRT & SecureFX 介绍 1.1 SecureCRT SecureCRT 是一款终端仿真软件,和 Putty 的功能类似. 不过相比Putty比较简单的功能,Secu ...