• P2934 [USACO09JAN]Safe Travel G


    题目

    给定一个无向图,保证从1号点到所有点的最短路只有一条,现在对于每一个点询问:如果把1号点到这个点的最短路径的最后一条边断掉,那么到这个点的最短路变成了多少?

    分析

    首先我们发现最短路只有一条,其实就是在提示我们建出最短路树。

    那么现在每一条树外面的边其实就有各自的贡献,对于一条边,它可以更新(u o lca)(v o lca) 的路径上的每一个点 (i),值为 (val(u,v)+dis_u+dis_v-dis_i)

    我们发现直接去修改更新这些点的答案似乎并不好做。

    但是有这样的一个性质:对于每一个点来说,其本身被哪些边更新完了,上面柿子的最后一项是确定的,无论是什么边来更新这个点的答案,后面的那一项都是个定值。

    那么现在我们的困难就解决了,我们难以修改就是因为最后的一项是个变量,对于所有点来说不一样,就不好修改,而现在我们可以先忽略这个,那么我们就可以只维护前面的部分了。

    于是对于每一个点的答案,我们贪心地去更新,也就是把所有边按照(val(u,v)+dis_u+dis_v)排序,然后更新路径,再把路径上的所有点用并查集合并起来,因为这些点的答案已经确定了,之后不会再被用到。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    #define int long long
    const int N=7e5+5,INF=1e12+7;
    int n,m;
    int head[N],to[N<<1],nex[N<<1],val[N<<1],fr[N<<1],idx=1;
    inline void add(int u,int v,int w){
    	nex[++idx]=head[u];
    	fr[idx]=u;
    	to[idx]=v;
    	val[idx]=w;
    	head[u]=idx;
    	return ;
    }
    #define PII pair<int,ll>
    priority_queue<PII,vector<PII>,greater<PII> >q;
    int pre[N],num[N];
    ll dis[N];
    bool vis[N<<1];
    void Dijkstra(){
    	memset(dis,0x3f,sizeof(dis));
    	dis[1]=0;q.push(make_pair(0,1));
    	while(!q.empty()){
    		PII t=q.top();q.pop();
    		int x=t.second;ll d=t.first;
    		if(vis[x]) continue;vis[x]=true;
    		for(int i=head[x];i;i=nex[i]){
    			int y=to[i];
    			if(dis[y]>dis[x]+val[i]) dis[y]=dis[x]+val[i],q.push(make_pair(dis[y],y)),pre[y]=x,num[y]=i;
    		}
    	}
    	return ;
    }
    vector<int>vec[N];
    ll Ans[N];
    int top1;
    struct Edge{
    	int u,v,val,lca;
    	Edge(int u=0,int v=0,int val=0,int lca=0):u(u),v(v),val(val),lca(lca){}
    	inline bool operator < (const Edge &B)const{return val<B.val;}
    }sta[N<<1];
    inline void cmin(ll &x,int y){if(y<x) x=y;}
    int dep[N],siz[N],fa[N],son[N],top[N];
    void dfs1(int x,int f){
    	dep[x]=dep[f]+1,siz[x]=1,fa[x]=f;
    	for(auto y:vec[x]){
    		dfs1(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]]) son[x]=y; 
    	}
    	return ;
    }
    void dfs2(int x,int f){
    	if(x==son[fa[x]]) top[x]=top[fa[x]];
    	else top[x]=x;
    	if(son[x]) dfs2(son[x],x);
    	for(auto y:vec[x]) if(y!=son[x]) dfs2(y,x);
    	return ;
    }
    inline int QueryLca(int u,int v){
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int fa1[N];
    int Getfa(int x){return x==fa1[x]?x:fa1[x]=Getfa(fa1[x]);}
    void Solve(int x,int Rt,int v){
    	if(x==Rt||!x) return ;
    	if(!vis[x]) Ans[x]=v-dis[x],vis[x]=true;
    	if(fa[Getfa(fa[x])]!=Rt) fa1[x]=Getfa(fa[x]);
    	Solve(Getfa(fa[x]),Rt,v); 
    	return ;
    }
    signed main(){
    //	system("fc my.out P2934_6.out");
    //	freopen("P2934_6.in","r",stdin);
    //	freopen("my.out","w",stdout);
    	read(n),read(m);
    	for(int i=1;i<=m;i++){
    		int u,v,w;
    		read(u),read(v),read(w);
    		add(u,v,w),add(v,u,w);
    	}
    	Dijkstra();
    	memset(vis,0,sizeof(vis));memset(Ans,0x3f,sizeof(Ans));
    	for(int i=1;i<=n;i++) vec[pre[i]].push_back(i),vis[num[i]]=vis[num[i]^1]=true;
    	dfs1(1,0),dfs2(1,0);
    	for(int i=2;i<=idx;i++){
    		if(vis[i]||vis[i^1]) continue;
    		vis[i]=true;sta[++top1]=Edge(fr[i],to[i],dis[fr[i]]+dis[to[i]]+val[i],QueryLca(fr[i],to[i]));
    	}
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=n;i++) fa1[i]=i;
    	sort(sta+1,sta+top1+1);
    	for(int i=1;i<=top1;i++){
    		int x=Getfa(sta[i].u),y=Getfa(sta[i].v);
            while(x!=y){
                if(dis[x]<dis[y]) swap(x, y);
                Ans[x]=sta[i].val-dis[x];
                fa1[x]=fa[x];
                x=Getfa(x);
            }
    	}
    	for(int i=2;i<=n;i++) write(Ans[i]>INF?-1:Ans[i]),putchar('
    ');
    	return 0;
    }
    
    

    总结

    这样的“维护过程中不好维护”的某一项,如果在对于其自身的答案这一项具有不变性的话,我们就可以先不考虑这一项,然后最后更新答案的时候再加进去即可。

    这样的思路非常巧妙,需要注意。

  • 相关阅读:
    Linux下Rootkit的另类检测
    用iptables抗御SYN Flood攻击
    用iptables抗御SYN Flood攻击
    突破极限 解决大硬盘上安装Sco Unix新思路
    突破极限 解决大硬盘上安装Sco Unix新思路
    安装、配置Vmware Esx Server 3.5视频全过程
    安装、配置Vmware Esx Server 3.5视频全过程
    应该如何对企业局域网性能传输进行测试分析
    Leetcode-944 Delete Columns to Make Sorted(删除列以使之有序)
    Leetcode-941 Valid Mountain Array(有效的山脉数组)
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14932444.html
Copyright © 2020-2023  润新知