[删边最短路 并查集||线段树] BZOJ 2725 [Violet 6]故乡的梦 & 4400 tjoi2012 桥

66 篇文章 0 订阅
24 篇文章 0 订阅
首先求出一条S到T的最短路P,如果不是最短路上的边删了肯定不影响答案。
接着证明去掉一条边(u,v)之后最短路一定是这样存在一条边(x,y),然后最短路径是S->x->y->T,并且S->x,y->T都是原图中的最短路。
考虑S的最短路径图和T的最短路径图。
于是只要考虑一条边(x,y),然后求出S到x的最短路和这条最短路最早什么时候离开P,记作x’,同理求出y’。
于是(x,y)这条边可以更新x’到y’之间的答案。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<queue>
#include<cstring>
#define U G[p].u
#define V G[p].v
#define W G[p].w
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,int> abcd;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int M=200005;
const int N=200005;

/*struct Queue{
  priority_queue<abcd,vector<abcd>,greater<abcd> > Q,del;
  void maintain(){ while (!Q.empty()&&!del.empty()&&Q.top()==del.top()) Q.pop(),del.pop(); }
  void push(abcd x){ maintain(); Q.push(x); }
  void pop(){ maintain(); if (!Q.empty()) Q.pop(); }
  void erase(abcd x){ maintain(); del.push(x); }
  abcd top(){ maintain(); return Q.top(); }
  bool empty(){ maintain(); return Q.empty(); }
  void clear() { while (!Q.empty()) Q.pop(); while (!del.empty()) del.pop(); }
}Q;*/

struct edge{
  int u,v,w,next;
}G[M<<1];
int head[N],inum=1;
int fla[M<<1];

inline void add(int u,int v,int w,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

namespace DIJ{
#define val(x) dis[H[x]]
#define K(x) (x<<1|1)>cnt?(x<<1):(val(x<<1)<val(x<<1|1)?(x<<1):(x<<1|1))
	ll* dis;
	int H[N];
	int cnt,back[N],vst[N];
	
	inline void Swp(int x,int y){
	  swap(H[x],H[y]); swap(back[H[x]],back[H[y]]);
	}
	inline void Up(int x){
	  for (;x && val(x)<val(x>>1);x>>=1) Swp(x,x>>1);			
	}
	inline void Down(int x){
	  for (int tmp;(x<<1)<=cnt && val(x)>val(tmp=K(x));x=tmp) Swp(x,tmp);
	}
	inline void Dij(int S,int n,ll *dis){
	  int u; DIJ::dis=dis;
	  cnt=0; H[++cnt]=S; back[S]=cnt; dis[S]=0; vst[S]=1;
	  for (int i=1;i<=n;i++)
	    if (i!=S)
	      H[++cnt]=i,back[i]=cnt,dis[i]=1LL<<60,vst[i]=0;
	  for (int i=1;i<n;i++){
	    u=H[1]; vst[H[1]]=1;
	    Swp(1,cnt--); Down(1);
	    for (int p=head[u];p;p=G[p].next)
	      if (!vst[V] && dis[V]>dis[U]+G[p].w){
		dis[V]=dis[U]+G[p].w;
		Up(back[V]);
	      }
	  }
	}
}

int n,m;
ll disS[N],disT[N]; 

/*inline void Dij(int S,ll *dis){
  Q.clear();
  for (int i=1;i<=n;i++) dis[i]=1LL<<60;
  dis[S]=0; Q.push(abcd(0,S));
  for (int i=1;i<=n;i++){
    abcd t=Q.top(); Q.pop();
    int u=t.second;
    for (int p=head[u];p;p=G[p].next)
      if (dis[V]>dis[u]+G[p].w){
	Q.erase(abcd(dis[V],V));
	dis[V]=dis[u]+G[p].w;
	Q.push(abcd(dis[V],V));
      }
  }
}*/

int S,T;
int path[N],tot,inpath[N];
map<abcd,int> Map;
int fx[N],fy[N];

int lst[N],pnt;
int vst[N];
inline void dfs(int u,ll *dis){
  vst[u]=1;
  for (int p=head[u];p;p=G[p].next)
    if (!vst[V] && dis[V]==dis[u]+G[p].w)
      dfs(V,dis);
  lst[++pnt]=u;
}

int fat[N];
inline void init(int n){
  for (int i=1;i<=n;i++) fat[i]=i;
}
inline int Fat(int u){
  return u==fat[u]?u:fat[u]=Fat(fat[u]);
}

struct data{
  int l,r; ll w;
  data(int l=0,int r=0,ll w=0):l(l),r(r),w(w) { }
  bool operator < (const data &B) const{
    return w<B.w;
  }
}edges[M<<1];
int Tot;
ll ans[M];

int Que[N],l,r;
 
inline void getfir(int s,ll* dis,int* fir){  
	l=r=-1; Que[++r]=s; fir[s]=inpath[s];  
    while (l<r){  
        int u=Que[++l];
        for (int p=head[u];p;p=G[p].next)  
            if (!inpath[V] && !fir[V] && dis[V]==dis[u]+G[p].w)
                Que[++r]=V,fir[V]=inpath[s];  
    }  
}  

void getway(){  
    for (int x=S,last=-1;;){  
        inpath[x]=++tot,path[tot]=x;  
        if (x==T) break;  
        for (int p=head[x];p;p=G[p].next)  
            if (V!=last&&disS[x]+G[p].w+disT[V]==disS[T]){last=x,x=V;break;}  
    }  
}  

int main(){
  int iu,iv,iw;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m);
  for (int i=1;i<=m;i++){
    read(iu); read(iv); read(iw);
    add(iu,iv,iw,++inum); add(iv,iu,iw,++inum); Map[abcd(iu,iv)]=Map[abcd(iv,iu)]=inum>>1;
  }
  read(S); read(T);
  DIJ::Dij(S,n,disS);
  DIJ::Dij(T,n,disT); 
//  for (int i=T;i;i=pre[i]) path[++tot]=i; reverse(path+1,path+tot+1);
//  for (int i=1;i<=tot;i++) inpath[path[i]]=i;
  getway();
  for (int i=1;i<tot;i++) fla[Map[abcd(path[i],path[i+1])]]=1;
//  dfs(S,disS); reverse(lst+1,lst+pnt+1);
  for (int i=1;i<=tot;i++) getfir(path[i],disS,fx);  
  /*memset(fx,0x7f,sizeof(fx));
  for (int i=1;i<=tot;i++) fx[path[i]]=i;
  for (int i=1;i<=pnt;i++)
    for (int p=head[lst[i]];p;p=G[p].next)
      if (!inpath[V] && disS[V]==disS[G[p].u]+G[p].w)
	fx[V]=min(fx[V],fx[lst[i]]);
  pnt=0; cl(vst);*/
//  dfs(T,disT); reverse(lst+1,lst+pnt+1);
  for (int i=tot;i;i--) getfir(path[i],disT,fy);
  /*for (int i=1;i<=tot;i++) fy[path[i]]=i;
  for (int i=1;i<=pnt;i++)
    for (int p=head[lst[i]];p;p=G[p].next)
      if (!inpath[V] && disT[V]==disT[G[p].u]+G[p].w)
	fy[V]=max(fy[V],fy[lst[i]]);*/
  for (int p=2;p<=inum;p++)
    if (!fla[p>>1])
      if (fx[U]<=fy[V]-1)
		edges[++Tot]=data(fx[U],fy[V]-1,disS[U]+W+disT[V]);
  sort(edges+1,edges+Tot+1);
  init(tot);
  for (int i=1;i<tot;i++) ans[i]=1LL<<60;
  for (int i=1;i<=Tot;i++)
    for (int j=Fat(edges[i].l);j<=edges[i].r;j=Fat(j))
      ans[j]=edges[i].w,fat[j]=j+1;
  int Q; ll Ans;
  read(Q);
  while (Q--){
    read(iu); read(iv); int p=Map[abcd(iu,iv)];
    if (!fla[p])
      Ans=disS[T];
    else{
      iu=inpath[iu],iv=inpath[iv]; if (iu>iv) swap(iu,iv);
      Ans=ans[iu];
    }
    if (Ans==1LL<<60)
      printf("Infinity\n");
    else
      printf("%lld\n",Ans);
  }
  return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值