BZOJ 1576 [USACO]安全路经Travel (树剖+线段树)
题目大意:
给你一张无向图,求1到其他节点 不经过最短路的最后一条边 的最短路长度,保证每个节点的最短路走法唯一
神题,$USACO$题目的思维是真的好
先$dijkstra$出最短路树
对于每个节点,符合条件的走法必须满足,不经过它和它父亲之间的连边
显然只能从它的某个子节点走向它,就像绕了一圈
可以证明最优的合法路径一定只经过一条非树边,因为最短路方案唯一
如果还经过另外一条非树边,不论这条边在哪,都肯定会绕远
对于一条非树边$e<x,y>$,它连接了两个节点$x,y$,它们的$lca$是$f$
显然$x$到$f$路径上的某个点$S$(除了$f$点),都存在一条合法路径,从根节点沿树边走到$y$,经过$e<x,y>$走到$x$,再向上沿树边走到$S$
这段路径的长度是$dis_{x}+dis_{y}+dis_{e<x,y>}-dis_{S}$
对于$y$到$f$的路径也是同理
上面的式子可以用线段树+树链剖分序维护
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 1010
#define M1 2010
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 233333333
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,m;
struct Edge{
int to[M1*],nxt[M1*],val[M1*],head[N1],cte;
void ae(int u,int v,int w)
{cte++,to[cte]=v,nxt[cte]=head[u],val[cte]=w,head[u]=cte;}
}E,T;
struct SEG{
int mi[T1];
void pushdown(int rt)
{
mi[rt<<]=min(mi[rt<<],mi[rt]);
mi[rt<<|]=min(mi[rt<<|],mi[rt]);
}
void build(int l,int r,int rt)
{
mi[rt]=inf;
if(l==r) return;
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
}
void update(int L,int R,int l,int r,int rt,int w)
{
if(L<=l&&r<=R) {mi[rt]=min(mi[rt],w);return;}
int mid=(l+r)>>; pushdown(rt);
if(L<=mid) update(L,R,l,mid,rt<<,w);
if(R>mid) update(L,R,mid+,r,rt<<|,w);
}
int query(int x,int l,int r,int rt)
{
if(l==r) return mi[rt];
int mid=(l+r)>>; pushdown(rt);
if(x<=mid) return query(x,l,mid,rt<<);
else return query(x,mid+,r,rt<<|);
}
}s; int dis[N1],use[N1],fa[N1],la[N1],ist[M1*];
struct node{
int id,d;
friend bool operator < (const node &s1,const node &s2)
{return s1.d>s2.d;}
};
void dijkstra()
{
int j,v,u;
memset(dis,0x3f,sizeof(dis));
priority_queue<node>q;
dis[]=,q.push((node){,});
while(!q.empty())
{
node k=q.top(); q.pop(); u=k.id;
if(use[u]) continue; use[u]=;
for(j=E.head[u];j;j=E.nxt[j]){
v=E.to[j];
if(dis[v]>dis[u]+E.val[j])
dis[v]=dis[u]+E.val[j],q.push((node){v,dis[v]}),fa[v]=u,la[v]=j;
}
}
} int dep[N1],sz[N1],tp[N1],son[N1],st[N1],id[N1],tot;
void dfs1(int u,int dad)
{
for(int j=T.head[u];j;j=T.nxt[j])
{
int v=T.to[j]; if(v==dad) continue;
dep[v]=dep[u]+; dfs1(v,u); //fa[v]=u;
sz[u]+=sz[v]; son[u]=sz[v]>sz[son[u]]?v:son[u];
}
sz[u]++;
}
void dfs2(int u)
{
st[u]=++tot,id[tot]=u;
if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]);
for(int j=T.head[u];j;j=T.nxt[j])
{
int v=T.to[j];
if(v==son[u]||v==fa[u]) continue;
tp[v]=v; dfs2(v);
}
}
void update(int x,int y,int w)
{
int px=x,py=y;
while(tp[x]!=tp[y])
{
if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
s.update(st[tp[x]],st[x],,n,,dis[px]+dis[py]+w);
x=fa[tp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
if(x!=y) s.update(st[x]+,st[y],,n,,dis[px]+dis[py]+w);
} void solve()
{
int x,y,i,j,v,ans; dijkstra(); s.build(,n,);
for(i=;i<=n;i++) T.ae(fa[i],i,E.val[la[i]]),ist[la[i]]=;
dep[]=,dfs1(,-); tp[]=,dfs2();
for(j=;j<=m*;j+=)
{
if(ist[j]||ist[j+]) continue;
x=E.to[j],y=E.to[j+];
update(x,y,E.val[j]);
}
for(i=;i<=n;i++)
{
ans=s.query(st[i],,n,);
if(ans==inf) printf("-1\n");
else printf("%d\n",ans-dis[i]);
}
} int main()
{
scanf("%d%d",&n,&m);
int i,j,x,y,z;E.cte=;
for(i=;i<=m;i++) x=gint(),y=gint(),z=gint(),E.ae(x,y,z),E.ae(y,x,z);
solve();
return ;
}
BZOJ 1576 [USACO]安全路经Travel (树剖+线段树)的更多相关文章
- BZOJ_2238_Mst_树剖+线段树
BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...
- BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树
BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...
- BZOJ_2157_旅游_树剖+线段树
BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...
- 【BZOJ5210】最大连通子块和 树剖线段树+动态DP
[BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...
- [LNOI2014]LCA(树剖+线段树)
\(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...
- [CF1007D]Ants[2-SAT+树剖+线段树优化建图]
题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...
- LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)
题面 传送门 题解 先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y ...
- BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...
- 【bzoj4699】树上的最短路(树剖+线段树优化建图)
题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...
随机推荐
- HDU 5322 Hope (分治NTT优化DP)
题面传送门 题目大意: 假设现在有一个排列,每个数和在它右面第一个比它大的数连一条无向边,会形成很多联通块. 定义一个联通块的权值为:联通块内元素数量的平方. 定义一个排列的权值为:每个联通块的权值之 ...
- SQLAlchemy小知识点
1.创建数据库模型的时候增加添加上注释SQLAlchemy1.2新增了comment参数telephone = db.Column(db.String(11), nullable=False, com ...
- Linux 基础入门一
操作系统1.简介OS: Operating System,通用目的的软件程序操作系统的内核(kernel): 操作系统其实也是一组程序.这组程序的重点在于管理计算机的所有活动及驱动系统中的所有硬件: ...
- Docker学习总结(14)——从代码到上线, 云端Docker化持续交付实践
2016云栖大会·北京峰会于8月9号在国家会议中心拉开帷幕,在云栖社区开发者技术专场中,来自阿里云技术专家罗晶(瑶靖)为在场的听众带来<从代码到上线,云端Docker化持续交付实践>精彩分 ...
- 使用Struts2和jQuery EasyUI实现简单CRUD系统(五)——jsp,json,EasyUI的结合
这部分比較复杂,之前看过自己的同学开发一个选课系统的时候用到了JSON,可是一直不知道有什么用.写东西也没用到.所以没去学他.然后如今以这样的怀着好奇心,这是做什么用的,这是怎么用的.这是怎么结合的心 ...
- Windows 8.1内置微软五笔输入法
微软五笔输入法採用86版编码,不是Windows 8.1系统的中文语言的缺省输入法,你在使用它之前须要把它加入到系统输入法中. 在控制面板双击"",然后加入微软五笔输入法. wat ...
- Leetcode--easy系列2
#14 Longest Common Prefix Write a function to find the longest common prefix string amongst an array ...
- wpf 全局异常捕获处理
/// <summary> /// App.xaml 的交互逻辑 /// </summary> public partial class App : Application { ...
- c8---递归
// // main.c // 递归函数 // // Created by xiaomage on 15/6/7. // Copyright (c) 2015年 xiaomage. All right ...
- Android 编程下获得应用程序的签名
说明:应用程序的签名被封装在 packageInfo 中,所以我们要获得应用程序的签名就需要获得 PackageManager 来获得包含有签名信息的 packageInfo,再通过 packageI ...