【hdu3238】Finding the Most Vital Node of a Shortest Path

48 篇文章 0 订阅
23 篇文章 0 订阅

题意:给定s,t,求出无向图上,去掉第i个点之后的最短路径极其路径条数,每个i都要计算出来。

出个论文题就算了,还非要算方案...

先求出最短路树,考虑去掉节点i,我们可以分出三层,一层节点集合是节点i的子树外的节点,称为U,一层是节点i的若干子树但去除包括汇点的子树,称为O,一层是汇点所在的i的一棵子树,称为D;那么如果去掉i节点,最短路的构成有两种,一种是经过U的若干节点跨过一条边到D再经过若干节点到t,另一种是经过U的若干节点再经过O的若干节点再经过若干D的节点到t。

观察这两种路径,在U和D里面的最短距离一遍预处理就出来,而在O中的却比较麻烦,因为要算出不经过i的在O中的最短路,因此必须用到最短路树的性质。

首先通过观察,可以发现几个性质:如果按从s-t的顺序访问spt的每个点i,那么其余点会依次从D->O->U,也就是说,每个点只会属于某一个i的O集合,而在其他情况要么是D要么是U,因此就可以依次预处理每一个点i的Oi而互不影响,具体就是通过Ui->Oi的边做出Oi中点的初值,然后再在Oi的内部做迪杰斯特拉,在内部更新,而Di明显不会影响。

接下来是通过s到所有点的距离,所有点到t的距离以及每个点在其属于的Oi集合不经过其i到s的距离更新答案,具体来说就是还是依次按s-t的顺序做,依次递推出i的答案。

用个map维护一下到t的若干路径长度与方案,现在已经处理了rt[i],对于i点来说其Oi中的点将从Di变过来,而以前可能用U->D的路径更新过,因此要先删掉这些路径,而他又由D变成了新的O,因此要再用其O->D来加上一些最短路径,处理完这些后,点i的答案就可以算出来了,然后再把Oi中的点变为U,删掉其Oi->D的路径,添入一些U->D的路径。

然后这个题除了要求最短路还有求方案就更麻烦,首先是求O中的最短路的时候,除了要继承U的最短路,还要继承其方案,然后是因为如果是任意的最短路树的话可能存在D->U的路径,而这种路径会经过i,导致在算i的答案的时候计算了一条D->U->D的不合法路径,譬如数据:

4 5 3 4 X

3 2 3

3 1 6

2 1 5

2 4 2

4 1 1

解决方案是从t往s建树,每次把最短路图上的没被访问过的点给扯到他的子树中来,这样就可以避免有D->U的路径。

如果一个点不在我们默认的最短路径上,它有可能影响方案数,此时只需减掉经过它的方案数即可。

还有一个坑的地方,我的处理方法每次要减掉一些数,而这个奇怪的输出要取模,这就导致每次我不知道减去之后是真为0还是模为0...但这数据还是让我过了

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <utility>
const int oo=1073741819,mo=19880830;
using namespace std;
vector <int> stack;
map < int , long long > Map;
int next[2000000],sora[2000000],cost[2000000],st[500000],u[500000],tail[500000],b[2000000];
int v[500000],col[500000],d[500000],rt[3][500000];
int ss,n,m,m1,s,t,q;
struct dist{
	int m;
	long long c;
}D[3][500000],ans[500000];
void origin()
{
    ss=n;
    for (int i=1;i<=n;i++) tail[i]=i,next[i]=0;
    for (m1=1;m1<=n+2;m1<<=1) ;
    for (int i=1;i<=m1+m1;i++) b[i]=0;
    for (int i=1;i<=n;i++) b[i+m1]=i,d[i]=oo;
    for (int i=1;i<=n;i++) {
        v[i]=col[i]=0;
        for (int j=0;j<=2;j++)
            D[j][i].m=oo,D[j][i].c=0,rt[j][i]=0;
        ans[i].m=oo,ans[i].c=0;
    }
  	Map.clear(),stack.clear();
}
void link(int x,int y,int z)
{
	++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,cost[ss]=z,next[ss]=0;
	++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,cost[ss]=z,next[ss]=0;
}
int mind(int x,int y)
{
    return (d[x]<d[y]) ? x : y;
}
void change(int x,int w)
{
    d[x]=w;
    for (x=((x+m1)>>1);x;x>>=1) 
        b[x]=mind(b[x<<1],b[(x<<1)+1]);
}
void dij(int e,int &r)
{
    for (;d[b[1]]!=oo;) {
        int x=b[1],cos=d[x];
        st[++r]=x,D[e][x].m=cos;
        change(x,oo);
        for (int i=x,ne;next[i];) {
            i=next[i],ne=sora[i];
            if (d[ne]!=oo && cos+cost[i]<d[ne] && v[x]==v[ne]) {
                rt[e][ne]=x;
                change(ne,cos+cost[i]);
            }
        }
    }
}
void spfa(int s,int e)
{
    for (int i=0;i<=n;i++) change(i,oo+1);
    change(s,0);
    int r=0;
    dij(e,r);
    D[e][st[1]].c=1;
    for (int i=1;i<=r;i++) {
        int x=st[i];
        for (int i=x,ne;next[i];) {
            i=next[i],ne=sora[i];
            if (D[e][x].m+cost[i]==D[e][ne].m)
                (D[e][ne].c+=D[e][x].c)%=mo;
        }
    }
}
void dfs(int x,int level)
{
	stack.push_back(x);
	v[x]=level;
	for (int i=x,ne;next[i];) {
		i=next[i],ne=sora[i];
		if (D[0][x].m+cost[i]==D[0][ne].m && !v[ne] && !col[ne]) dfs(ne,level);
	}
}
bool cmp(int i,int j)
{
	if (v[i]!=v[j]) return v[i]>v[j];
	return col[i]<col[j];
}
void updata(int w,long long c)
{
	map < int , long long > :: iterator it=Map.find(w);
	if (it==Map.end()) {
		Map[w]=c;
		return ;
	}
	it->second=((it->second+c)%mo+mo)%mo;
	if (!(it->second)) Map.erase(it);
}
void add_o_d(int x,int e)
{
	for (int i=x,ne;next[i];) {
    i=next[i],ne=sora[i];
    if (v[ne]<v[x]) {
    	int cos=D[2][x].m+cost[i]+D[1][ne].m;
  		long long tmp=(D[2][x].c*D[1][ne].c)%mo;
  		if (!tmp) return ; 
    	updata(cos,tmp*e);
  	}
  }
}
void add_u_d(int x,int e)
{
	for (int i=x,ne;next[i];) {
    i=next[i],ne=sora[i];
    if (e*v[ne]>e*v[x]) {
      int cos;
      long long tmp;
      if (e==1) {
      	cos=D[0][ne].m+cost[i]+D[1][x].m;
      	tmp=(D[0][ne].c*D[1][x].c)%mo;
      }
      else {
      	cos=D[0][x].m+cost[i]+D[1][ne].m;
      	tmp=(D[0][x].c*D[1][ne].c)%mo;
      }
      if (!tmp) return ;
      updata(cos,-tmp*e);
    }
  }
}
int main()
{
    for (int test=1;scanf("%d%d%d%d%d",&n,&m,&s,&t,&q)==5;test++) {
    		if (!n && !m && !s && !t && !q) break;
        origin();
        for (int i=1;i<=m;i++) {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            link(x,y,z);
        }
        spfa(s,0);
        spfa(t,1);
        for (int i=t;i;i=rt[0][i]) col[i]=1;
        for (int i=t,cnt=1;i;i=rt[0][i],++cnt) {
        	stack.clear();
        	dfs(i,cnt);
        	for (int i=1;i<(int)stack.size();i++) {
        		int x=stack[i];
        		d[x]=oo+1;
        		for (int i=x,ne;next[i];) {
        			i=next[i],ne=sora[i];
        			if (!v[ne] && D[0][ne].m+cost[i]<d[x]) 
        				change(x,D[0][ne].m+cost[i]);
        		}
        	}
        	int r=0;
        	dij(2,r);
        	for (int i=1;i<=r;i++) {
        		int x=st[i];
        		for (int i=x,ne;next[i];) {
        			i=next[i],ne=sora[i];
        			if (!v[ne]) {
        				if (D[0][ne].m+cost[i]==D[2][x].m)
        					(D[2][x].c+=D[0][ne].c)%=mo;
        			}	
        		}
        		for (int i=x,ne;next[i];) {
        			i=next[i],ne=sora[i];
        			if (v[ne]==v[x] && !col[ne]) {
        				if (D[2][x].m+cost[i]==D[2][ne].m)
        					(D[2][ne].c+=D[2][x].c)%=mo;
        			}
        		}
        	}
        }
        for (int i=1;i<=n;i++) u[i]=i;
        sort(u+1,u+n+1,cmp);
        for (int i=1;i<=n;i++) {
        	int x=u[i];
        	add_u_d(x,1);
        	if (!col[x]) {
        		add_o_d(x,1);
        	}
        	else {
        		if (Map.empty()) ans[x].m=oo,ans[x].c=0;
        		else {
        			map < int , long long > :: iterator it;
        			it=Map.begin();
        			if (it!=Map.end())
        				ans[x].m=it->first,ans[x].c=it->second;
        		}
        		for (int j=i-1;j>=1 && v[u[j]]==v[u[i]];j--)  
        			add_o_d(u[j],-1);
        		for (int j=i;j>=1 && v[u[j]]==v[u[i]];j--)  
        			add_u_d(u[j],-1);
        	}
        }
        printf("Case %d:",test);
        for (int i=1;i<=q;i++) {
        	int x; 
        	scanf("%d",&x);
        	long long Ans=0,X=1;
        	for (int j=1;j<=n;j++) {
        		if (ans[j].m==oo) {
        			if (col[j]) ans[j].m=0,ans[j].c=0;
        			else {
        				ans[j].m=D[0][t].m,ans[j].c=D[0][t].c;
        				int x=j;
        				for (int i=x,ne;next[i];) {
        					i=next[i],ne=sora[i];
        					if (D[0][x].m+cost[i]+D[1][ne].m==D[0][t].m) ans[j].c=((ans[j].c-D[0][x].c*D[1][ne].c)%mo+mo)%mo;
        				}
        				if (ans[j].m==oo) ans[j].m=0,ans[j].c=0;
        			}
        		}
        		Ans=(Ans+X*ans[j].m)%mo;
        		X=(X*x)%mo;
        		Ans=(Ans+ans[j].c*X)%mo;
        		X=(X*x)%mo;
        	}
        	printf(" %lld",Ans);
        }
        printf("\n\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值