• [bzoj2725]故乡的梦——最短路+线段树


    题目大意:

    给定一个带权无向图,每次询问删除一条边之后从S到T的最短路是多少?(各个询问之间独立)

    思路:

    如果删除的边不在最短路中或者可以被替换,那么答案即为最短路。
    如果删除的边在最短路中并且不可以被替换,考虑将这条边删除的新图:
    假设原来的最短路为(S->T),那么新的最短路一定是(S->u->x->y->v->T)(其中u,v在原来的最短路上,x,y不在原来的最短路上)
    于是我们发现如果删除了这条边之后S和T联通,那么一定会经过形如(x->y)这样的路径,即经过原本不在最短路中的边。
    并且对于(x->y)中的一条边(uu,vv),(S->uu)(vv->T)一定是两条最短的路径于是我们枚举出每一条不在最短路中的边(uu,vv),并计算出对应的最早的u和最晚的v,用强制经过(uu,vv)的最短路去更新u和v中间缺失的那些边的答案。为了方便,在具体实现的时候随意提出一条(S->T)的最短路并把它当作唯一的最短路即可。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<endl
    #define pii pair<ll,int>
    #define fi first
    #define se second
    #define mk make_pair
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("bzoj2725.in","r",stdin);
    	freopen("bzoj2725.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	T __=0,mul=1; char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')mul=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    	_=__*mul;
    }
    
    const int maxn=2e5+10;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    int n,m,q,ss,tt;
    int beg[maxn],to[maxn<<1],las[maxn<<1],cnte=1;
    ll w[maxn<<1],dis[maxn],ddis[maxn];
    int pre[maxn],nex[maxn],pre_node[maxn],ls[maxn],cnt_ls,num[maxn],cnt_num;
    int ps[maxn],pt[maxn];
    map<int,int>mp[maxn];
    
    void add(int u,int v,ll val){
    	las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;
    	las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; w[cnte]=val;
    }
    
    void Dijkstra_pre(){
    	priority_queue<pii,vector<pii>,greater<pii> >qu;
    	memset(dis,63,sizeof(dis));
    	dis[ss]=0; qu.push(mk(0,ss));
    	while(!qu.empty()){
    		int u=qu.top().se; ll d=qu.top().fi;
    		qu.pop();
    		if(dis[u]!=d)continue;
    		for(int i=beg[u];i;i=las[i]){
    			int v=to[i];
    			if(d+w[i]<dis[v]){
    				pre[v]=i/2;
    				pre_node[v]=u;
    				dis[v]=d+w[i];
    				qu.push(mk(dis[v],v));
    			}
    		}
    	}
    
    	int p=tt;
    	while(pre_node[p]){
    		num[pre[p]]=++cnt_num;
    		nex[pre_node[p]]=pre[p];
    		ls[++cnt_ls]=p;
    		p=pre_node[p];
    	}
    	ls[++cnt_ls]=ss;
    	REP(i,1,cnte/2)if(num[i])
    		num[i]=cnt_num-num[i]+1;
    }
    
    void Dijkstra1(){
    	priority_queue<pii,vector<pii>,greater<pii> >qu;
    	memset(ddis,63,sizeof(ddis));
    	REP(i,1,cnt_ls){
    		ddis[ls[i]]=dis[ls[i]];
    		qu.push(mk(ddis[ls[i]],ls[i]));
    		ps[ls[i]]=ls[i];
    	}
    	while(!qu.empty()){
    		int u=qu.top().se; ll d=qu.top().fi;
    		qu.pop();
    		if(ddis[u]!=d)continue;
    		for(int i=beg[u];i;i=las[i]){
    			int v=to[i];
    			if(d+w[i]<ddis[v]){
    				ps[v]=ps[u];
    				ddis[v]=d+w[i];
    				qu.push(mk(ddis[v],v));
    			}
    			else if(d+w[i]==ddis[v] && ps[v]!=v && ps[u]<ps[v])
    				ps[v]=ps[u];
    		}
    	}
    }
    
    void Dijkstra2(){
    	priority_queue<pii,vector<pii>,greater<pii> >qu;
    	memset(ddis,63,sizeof(ddis));
    	REP(i,1,cnt_ls){
    		ddis[ls[i]]=dis[tt]-dis[ls[i]];
    		qu.push(mk(ddis[ls[i]],ls[i]));
    		pt[ls[i]]=ls[i];
    	}
    	while(!qu.empty()){
    		int u=qu.top().se; ll d=qu.top().fi;
    		qu.pop();
    		if(ddis[u]!=d)continue;
    		for(int i=beg[u];i;i=las[i]){
    			int v=to[i];
    			if(d+w[i]<ddis[v]){
    				pt[v]=pt[u];
    				ddis[v]=d+w[i];
    				qu.push(mk(ddis[v],v));
    			}
    			else if(d+w[i]==ddis[v] && pt[v]!=v && pt[u]<pt[v])
    				pt[v]=pt[u];
    		}
    	}
    }
    
    void init(){
    	read(n); read(m);
    	int u,v; ll val;
    	REP(i,1,m){
    		read(u),read(v),read(val);
    		add(u,v,val); mp[u][v]=mp[v][u]=cnte/2;
    	}
    	read(ss); read(tt);
    	Dijkstra_pre();
    	Dijkstra1();
    	Dijkstra2();
    }
    
    struct Segment_Tree{
    #define mid ((l+r)>>1)
    #define lc rt<<1
    #define rc rt<<1|1
    #define lson lc,l,mid
    #define rson rc,mid+1,r
    	ll Min[maxn<<2];
    	void update(int rt,int l,int r,int L,int R,ll x){
    		if(L>R || !L || !R)return;
    		if(L<=l && r<=R)Min[rt]=min(Min[rt],x);
    		else{
    			if(L<=mid)update(lson,L,R,x);
    			if(R>=mid+1)update(rson,L,R,x);
    		}
    	}
    	ll query(int rt,int l,int r,int p){
    		if(l==r)return Min[rt];
    		if(p<=mid)return min(Min[rt],query(lson,p));
    		return min(Min[rt],query(rson,p));
    	}
    }T;
    
    void work(){
    	memset(T.Min,63,sizeof(T.Min));
    	for(int i=2;i<=cnte;i+=2)if(!num[i/2]){
    		int u=to[i],v=to[i^1];
    		T.update(1,1,cnt_num,num[nex[ps[u]]],num[pre[pt[v]]],dis[u]+ddis[v]+w[i]);
    		T.update(1,1,cnt_num,num[nex[ps[v]]],num[pre[pt[u]]],dis[v]+ddis[u]+w[i]);
    	}
    	read(q);
    	int u,v;
    	REP(i,1,q){
    		read(u),read(v);
    		int id=mp[u][v];
    		if(!num[id])printf("%lld
    ",dis[tt]);
    		else{
    			ll ans=T.query(1,1,cnt_num,num[id]);
    			if(ans==inf)puts("Infinity");
    			else printf("%lld
    ",ans);
    		}
    	}
    }
    
    int main(){
    	File();
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    LeetCode 204
    华为OJ2051-最小的K个数(Top K问题)
    华为OJ1964-求解立方根(牛顿迭代法)
    华为OJ2288-合唱队(最长递增子序列)
    华为OJ2011-最长公共子串
    【Unix编程】进程间通信(IPC)
    可利用空间表(Free List)
    13.10 Scrapy 通用爬虫
    13.9 Scrapy 对接 Splash
    第十四章 分布式爬虫
  • 原文地址:https://www.cnblogs.com/ylsoi/p/9861086.html
Copyright © 2020-2023  润新知