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

来源:互联网 发布:2016年中日贸易数据 编辑:程序博客网 时间:2024/05/30 04:17

题意:给定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
原创粉丝点击