最短路 bzoj-3694

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

注释:$1\le n \le 4000$,$1\le m\le 10^5$。

想法:对于任意两个点uv,满足u和v之间直接相连了一条不在给出最短路树上的边,我们设这条边的长度为val(u,v)。对于任意的一个点i,它到根节点的最短路,也就是从根节点开始走最短路树所到达i的路径和,我们设为dis[i]。那么,对于u到lca(u,v)之间的任意一个点x,我们都可以从1(root)$\rightarrow$t$\rightarrow$v$\rightarrow$u$\rightarrow$x。我们可以用这条路径更新x的答案。这条路径的长度是dis[v]+val(u,v)+dis[u]-dix(x)。我们只需要令这样的(dis[v]+val(u,v)-dis[u])即可。显然,每两个这样满足条件的u和v,都可以更新从u到lca(u,v)之间的点和v到lca(u,v)之间的点,就是区间取min。这个操作我们可以用树链剖分+线段树实现。

最后,附上丑陋的代码... ...

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 1000000000
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,cnt1,cnt2=1,place;
int bin[12];
int u[100005],v[100005],w[100005];
int dis[100005],deep[100005],son[100005],fa[100005][12];
int pl[100005],belong[100005];
struct data{int to,next,v;}e[100005];int head[100005];
struct seg{int l,r,v,tag;}t[400005];
void ins(int u,int v,int w)
{
e[++cnt1].to=v;e[cnt1].next=head[u];head[u]=cnt1;e[cnt1].v=w;
}
void insert(int u,int v,int w)
{
ins(u,v,w);ins(v,u,w);
}
void dfs1(int x,int f)
{
for(int i=1;i<=11;i++)
if(bin[i]<=deep[x])fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
son[x]=1;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==f)continue;
deep[e[i].to]=deep[x]+1;
fa[e[i].to][0]=x;
dis[e[i].to]=dis[x]+e[i].v;
dfs1(e[i].to,x);
son[x]+=son[e[i].to];
}
}
void dfs2(int x,int chain)
{
belong[x]=chain;place++;pl[x]=place;
int k=0;
for(int i=head[x];i;i=e[i].next)
if(deep[e[i].to]>deep[x]&&son[e[i].to]>son[k])
k=e[i].to;
if(k)dfs2(k,chain);
for(int i=head[x];i;i=e[i].next)
if(deep[e[i].to]>deep[x]&&e[i].to!=k)
dfs2(e[i].to,e[i].to);
}
int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;i<=11;i++)
if(bin[i]&t)x=fa[x][i];
for(int i=11;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if(x==y)return x;
return fa[x][0];
}
void build(int k,int l,int r)
{
t[k].l=l;t[k].r=r;t[k].tag=inf;
if(l==r){t[k].v=inf;return;}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void pushdown(int k)
{
if(t[k].tag==inf||t[k].l==t[k].r)return;
int tag=t[k].tag;t[k].tag=inf;
t[k<<1].tag=min(t[k<<1].tag,tag);
t[k<<1|1].tag=min(t[k<<1|1].tag,tag);
if(t[k<<1].l==t[k<<1].r)t[k<<1].v=min(t[k<<1].v,tag);
if(t[k<<1|1].l==t[k<<1|1].r)t[k<<1|1].v=min(t[k<<1|1].v,tag);
}
void update(int k,int x,int y,int v)
{
pushdown(k);
int l=t[k].l,r=t[k].r;
if(x==l&&y==r)
{
t[k].tag=min(t[k].tag,v);
if(l==r)t[k].v=min(v,t[k].v);
return;
}
int mid=(l+r)>>1;
if(y<=mid)update(k<<1,x,y,v);
else if(x>mid)update(k<<1|1,x,y,v);
else {update(k<<1,x,mid,v);update(k<<1|1,mid+1,y,v);}
}
int ask(int k,int x)
{
pushdown(k);
int l=t[k].l,r=t[k].r;
if(l==r)return t[k].v;
int mid=(l+r)>>1;
if(x<=mid)return ask(k<<1,x);
else return ask(k<<1|1,x);
}
void solveupdate(int x,int f,int v)
{
while(belong[x]!=belong[f])
{
update(1,pl[belong[x]],pl[x],v);
x=fa[belong[x]][0];
}
if(x!=f)update(1,pl[f]+1,pl[x],v);
}
void solve()
{
build(1,1,n);
for(int i=1;i<cnt2;i++)
{
int t=lca(u[i],v[i]);
solveupdate(u[i],t,dis[u[i]]+dis[v[i]]+w[i]);
solveupdate(v[i],t,dis[u[i]]+dis[v[i]]+w[i]);
}
for(int i=2;i<=n;i++)
{
int t=ask(1,pl[i]);
if(t!=inf)printf("%d ",t-dis[i]);
else printf("-1 ");
}
}
int main()
{
//freopen("shortest.in","r",stdin);
//freopen("shortest.out","w",stdout);
bin[0]=1;for(int i=1;i<=12;i++)bin[i]=bin[i-1]*2;
n=read();m=read();
for(int i=1;i<=m;i++)
{
u[cnt2]=read();v[cnt2]=read(),w[cnt2]=read();
bool f=read();
if(!f)cnt2++;
else insert(u[cnt2],v[cnt2],w[cnt2]);
}
dfs1(1,0);dfs2(1,1);
solve();
return 0;
}

小结:考虑一个最值问题我们通常考虑一个式子可以更新什么样的情况下什么样的值,或者什么样的值可以被什么样情况的状态更新。比如说我们在进行倍增floyd时,我们是想到了每一条对于每一条最短路来讲,它的最后一条边可以从那些点来更新,从而想到矩阵来一遍一遍乘。而这个操作可以用矩乘优化。这道题也是同理,我们想到每一个点可以从哪种路径来进行更新,我们想到了如上述的方法,又因为给出的是最短路树,所以根节点到一个点的最短路一定是最短路树上的。更加说明了我们算法的正确性。

[bzoj3694]最短路_树链剖分_线段树的更多相关文章

  1. poj 3237 Tree(树链剖分,线段树)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description ...

  2. 【BZOJ3531】旅行(树链剖分,线段树)

    [BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...

  3. bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1536  Solved: 508[Submit][Status] ...

  4. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  5. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  6. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  7. HDU 4366 Successor(树链剖分+zkw线段树+扫描线)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...

  8. 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)

    [BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...

  9. 【洛谷5439】【XR-2】永恒(树链剖分,线段树)

    [洛谷5439][XR-2]永恒(树链剖分,线段树) 题面 洛谷 题解 首先两个点的\(LCP\)就是\(Trie\)树上的\(LCA\)的深度. 考虑一对点的贡献,如果这两个点不具有祖先关系,那么这 ...

  10. BZOJ.4515.[SDOI2016]游戏(树链剖分 李超线段树)

    BZOJ 洛谷 每次在路径上加的数是个一次函数,容易看出是树剖+李超线段树维护函数最小值.所以其实依旧是模板题. 横坐标自然是取个确定的距离标准.取每个点到根节点的距离\(dis[i]\)作为\(i\ ...

随机推荐

  1. cogs750栅格网络流(最小割)

    750. 栅格网络流 ★★☆   输入文件:flowa.in   输出文件:flowa.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] Bob 觉得一般图的最大流问题太 ...

  2. JavaScript--String 字符串对象属性

    访问字符串对象的属性length: stringObject.length; 返回该字符串的长度. var mystr="Hello World!"; var myl=mystr. ...

  3. C# 接口命名规范

    接口命名规范:1.大写约定PascalCasing:帕斯卡命名法,每个单词首字母大写应用场景:命名空间.类型.接口.方法.属性.事件.字段.枚举.枚举值eg:HtmlTag IOStream注意:两个 ...

  4. Unity3d dotween

    位置 1. 移动到指定位置 obj.transform.DOMove(, , ), 2f); a. 单方向可以用DOMoveX.DOMoveY.DOMoveZ b. 本地坐标系版本:DOLocalMo ...

  5. yum进程被占用

    使用yum安装软件的时候出现,/var/run/yum.pid 已被锁定,PID 为 6503 的另一个程序正在运行的问题 [root@localhost mysql]# yum install gc ...

  6. Vue动态创建组件方法

    组件写好之后有的时候需要动态创建组件.例如: 编辑文章页面,正文是一个富文本编辑器,富文本编辑器是一个第三方的组件,点击添加章节的时候需要动态的创建一个富文本编辑器这个时候怎么处理呢. 富文本编辑器也 ...

  7. input按钮的事件处理大全

    input按钮的事件处理大全   input按钮的事件处理大全1.<INPUT onclick=document.all.WebBrowser.ExecWB(1,1) type=button v ...

  8. CAD实现自定义实体夹点移动(com接口VB语言)

    主要用到函数说明: MxDrawXCustomEvent::MxDrawXCustomEntity::moveGripPointsAt 自定义实体事件,自定义实体夹点被移动,详细说明如下: 参数 说明 ...

  9. UpLoadify在IE下兼容问题

    一.在IE9.IE10不能点击的问题解决 解决方法:进入uploadify的js文件中,搜索SWFUpload.prototype.getFlashHTML,找到它对应的语句,将方法全部替换为以下内容 ...

  10. common_functions.h:64:24: error: token ""__CUDACC_VER__ is no longer supported.

    问题在复现工程https://github.com/google/hdrnet时出现. 现象: 解决: TensorFlow版本问题,升级到版本1.10.0之后,问题解决.