bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿

  这题可以用树链剖分或并查集写。树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用...

  首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了。

  并查集的方法就很巧妙了...把不在最短路径树上的边找出来,按照h[x]+dis[x][y]+h[y]从小到大排序。然后按排序后的边的顺序更新答案,被更新过了的必然不会被再次更新。更新的方法就是每次两个指针从x和y一步步向t靠近并更新沿途上没更新过的点,同时用并查集记录这些更改过的点的顶部,下次更新下面跑到这里的点直接就可以跳到没修改的地方。好像感觉其实就是把树剖改成用并查集来跳跳跳而已...

  只写了并查集,树剖的下次补(QAQ模板都不会打了已经

  UPD 2017.6.28:今天复习了下树剖,然后把这题写了嘿嘿嘿。这题最后只查询叶子结点,所以就不用上传了,非常好写。

树链剖分:

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=,inf=;
struct poi{int too,pre,sum;}e[maxn];
struct tjm{int sum,tag;}a[maxn];
struct zs{int x,y,len;}edge[maxn];
int n,m,x,y,z,flag,tot,tot2,cnt;
int last[maxn],size[maxn],fa[maxn],dep[maxn],son[maxn],w[maxn],top[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}
void dfs1(int x)
{
size[x]=;
for(int i=last[x];i;i=e[i].pre)
{
int too=e[i].too;
if(too!=fa[x])
{
fa[too]=x;
dep[too]=dep[x]+e[i].sum;
dfs1(too);
if(size[too]>size[son[x]])son[x]=too;
size[x]+=size[too];
}
}
}
void dfs2(int x,int tp)
{
w[x]=++cnt;top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=last[x];i;i=e[i].pre)
if(e[i].too!=son[x]&&e[i].too!=fa[x])
dfs2(e[i].too,e[i].too);
}
void pushdown(int x)
{
if(a[x].tag==inf)return;
int tag=a[x].tag;a[x].tag=inf;
a[x<<].tag=min(tag,a[x<<].tag);
a[x<<|].tag=min(tag,a[x<<|].tag);
}
void update(int x,int nl,int nr,int l,int r,int delta)
{
///if(nl!=nr)pushdown(x);
if(l<=nl&&nr<=r)a[x].tag=min(a[x].tag,delta);
else
{
//printf("%d %d\n",nl,nr);
int mid=(nl+nr)>>;
if(l<=mid)update(x<<,nl,mid,l,r,delta);
if(r>mid)update(x<<|,mid+,nr,l,r,delta);
}
}
ll query(int x,int nl,int nr,int num)
{
if(nl!=nr)pushdown(x);
if(nl==num&&nr==num)return a[x].tag;
else
{
int mid=(nl+nr)>>;
if(nl<=num&&num<=mid)return query(x<<,nl,mid,num);
if(mid<num&&num<=nr)return query(x<<|,mid+,nr,num);
}
}
void work(int x,int y,int len)
{
int f1=top[x],f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2])swap(x,y),swap(f1,f2);
update(,,cnt,w[f1],w[x],len);
x=fa[f1];f1=top[x];
}
if(x==y)return;
if(dep[x]<dep[y])swap(x,y);
update(,,cnt,w[son[y]],w[x],len);
}
void build(int x,int l,int r)
{
a[x].tag=inf;int mid=(l+r)>>;
if(l!=r)build(x<<,l,mid),build(x<<|,mid+,r);
}
int main()
{
read(n);read(m);
for(int i=;i<=m;i++)
{
read(x);read(y);read(z);read(flag);
if(!flag)edge[++tot2].x=x,edge[tot2].y=y,edge[tot2].len=z;
else add(x,y,z),add(y,x,z);
}
dfs1();dfs2(,);build(,,n);
for(int i=;i<=tot2;i++)
work(edge[i].x,edge[i].y,edge[i].len+dep[edge[i].x]+dep[edge[i].y]);
for(int i=;i<=n;i++)
{
int ans=query(,,cnt,w[i]);
if(ans!=inf)printf("%d ",ans-dep[i]);
else printf("-1 ");
}
return ;
}

并查集:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
const int maxn=;
struct zs{int too,sum,pre;}e[];
struct poi{int x,y,len;}edge[];
int n,m,x,y,z,flag,tot,tot2;
int fq[maxn],fa[maxn],h[maxn],v[maxn],last[maxn];
void add(int x,int y,int z){e[++tot].too=y;e[tot].sum=z;e[tot].pre=last[x];last[x]=tot;}
void dfs(int x,int fa)
{
for(int i=last[x];i;i=e[i].pre)
if(e[i].too!=fa)h[e[i].too]=h[x]+e[i].sum,fq[e[i].too]=x,dfs(e[i].too,x);
}
bool cmp(poi a,poi b){return a.len<b.len;}
int gf(int x){return x==fa[x]?x:fa[x]=gf(fa[x]);}
int main()
{
read(n);read(m);
for(int i=;i<=m;i++)
{
read(x);read(y);read(z);read(flag);
if(flag)add(x,y,z),add(y,x,z);
else edge[++tot2].x=x,edge[tot2].y=y,edge[tot2].len=z;
}
dfs(,);
for(int i=;i<=tot2;i++)
edge[i].len+=h[edge[i].x]+h[edge[i].y];
sort(edge+,edge++tot2,cmp);
for(int i=;i<=n;i++)
for(int i=;i<=n;i++)fa[i]=i;
for(int i=;i<=tot2;i++)
{
int x=gf(edge[i].x),y=gf(edge[i].y);
while(x!=y)
{
if(h[x]<h[y])swap(x,y);
if(!v[x])v[x]=i;
x=fq[x]=gf(fq[x]);
}
}
for(int i=;i<=n;i++)
if(v[i])printf("%d ",edge[v[i]].len-h[i]);
else printf("-1 ");
}

bzoj3694: 最短路(树链剖分/并查集)的更多相关文章

  1. hdu 5458 Stability(树链剖分+并查集)

    Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total ...

  2. HDU 5458 Stability (树链剖分+并查集+set)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条. 这题要倒着做才 ...

  3. [BZOJ2238]Mst 最小生成树+树链剖分/并查集

    链接 题解 先构建出最小生成树,如果删的是非树边,直接输出答案 否则问题转化为,把该边删掉后剩下两个联通块,两个端点分别在两个块内的最小边权,LCT可以维护 不妨换一种思考方向:考虑一条非树边可以代替 ...

  4. Bzoj 3694: 最短路 树链剖分

    3694: 最短路 Time Limit: 5 Sec  Memory Limit: 256 MBSubmit: 67  Solved: 34[Submit][Status][Discuss] Des ...

  5. [bzoj3694]最短路_树链剖分_线段树

    最短路 bzoj-3694 题目大意:给你一个n个点m条边的无向图,源点为1,并且以点1为根给出最短路树.求对于2到n的每个点i,求最短路,要求不经过给出的最短路树上的1到i的路径上的最后一条边. 注 ...

  6. [BZOJ1576] [BZOJ3694] [USACO2009Jan] 安全路径(最短路径+树链剖分)

    [BZOJ1576] [BZOJ3694] [USACO2009Jan] 安全路径(最短路径+树链剖分) 题面 BZOJ1576和BZOJ3694几乎一模一样,只是BZOJ3694直接给出了最短路树 ...

  7. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

  8. 数据结构(并查集||树链剖分):HEOI 2016 tree

    [注意事项] 为了体现增强版,题目限制和数据范围有所增强: 时间限制:1.5s 内存限制:128MB 对于15% 的数据,1<=N,Q<=1000. 对于35% 的数据,1<=N,Q ...

  9. 2019西北工业大学程序设计创新实践基地春季选拔赛 I Chino with Rewrite (并查集+树链剖分+线段树)

    链接:https://ac.nowcoder.com/acm/contest/553/I 思路:离线整棵树,用并查集维护下联通的情况,因为值只有60个,用2的x(1<=x<=60)次方表示 ...

随机推荐

  1. 第五篇 Flask组件之SQLAchemy及Flask-SQLAlchemy插件/Flask-Script/Flask-migrate/pipreqs模块

    SQLAlchemy组件 一. 介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然 ...

  2. Java开发工程师(Web方向) - 02.Servlet技术 - 期末考试

    Servlet课程考试 Servlet课程考试 Servlet课程考试 总分:55分 限定时间:120分钟 进入考试 答案已成功提交!请耐心等待成绩公布 Servlet课程考试: 1(12分) 简单谈 ...

  3. docker学习2

    今天继续学习docker! 搜索镜像 docker search centos 下载镜像 docker pull name(镜像名字) 查看镜像docker images 字段含义分析: TAG:仓库 ...

  4. 安装HIVE

    参考:https://cwiki.apache.org/confluence/display/Hive/GettingStarted 1.下载hive安装包     到apache官网或者其它地方下载 ...

  5. DFS中的奇偶剪枝(技巧)

    剪枝是什么,简单的说就是把不可行的一些情况剪掉,例如走迷宫时运用回溯法,遇到死胡同时回溯,造成程序运行时间长.剪枝的概念,其实就跟走迷宫避开死胡同差不多.若我们把搜索的过程看成是对一棵树的遍历,那么剪 ...

  6. C#中委托的发展与匿名函数

    匿名函数(C# 编程指南) 匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. 共有两种匿名函数 ...

  7. 使用cookies模拟登陆

    http://blog.csdn.net/a1099439833/article/details/51918955 使用cookies会话跟踪,保持cookies访问,对于cookies会失效的问题可 ...

  8. Linux环境PHP5.6升级7.1.8

    PHP7和HHVM比较PHP7的在真实场景的性能确实已经和HHVM相当, 在一些场景甚至超过了HHVM.HHVM的运维复杂, 是多线程模型, 这就代表着如果一个线程导致crash了, 那么整个服务就挂 ...

  9. java文件操作(普通文件以及配置文件的读写操作)

    转自:java文件操作(普通文件以及配置文件的读写操作) 读取普通文件 : /** * xiangqiao123欢迎你 如果对代码有疑问可以加qq群咨询:151648295 * * 读取MyFile文 ...

  10. dedecms给原模型添加新字段

    1.进入dedecms后台 2.点击核心=>频道模型=>内容模型管理(在这里可以看到dedecms预设的模型设置) 3.选中我们需要的模型,点击更改,跳入以下页面 4.点击字段管理(可以看 ...