BZOJ4227 : 城市

首先一遍Dijkstra求出S到每个点的最短路,并建出最短路图。

那么对于一条边,求在这条边不能使用的情况下,到首都S的最短时间会变长的点的数目,等价于求去掉这条边后在最短路图中不能从S出发到达的点的数目。

对于边x->y,新建一个点z,然后连边x->z->y,这样只需要计算从S到i上必须经过z的点数。

注意到最短路图是个DAG,我们可以按照拓扑序来建立必经点树:对于一个点x,它在必经点上的父亲为它所有前驱的lca,用倍增即可支持操作。

时间复杂度$O((n+m)\log n)$。

 

#include<cstdio>
typedef long long ll;
const int N=300010,M=400010,K=19;
const ll inf=1LL<<60;
int n,m,S,cnt,i,x,deg[N],g[N],v[M],w[M],nxt[M],ed;
int size[N],sum[N],id[N],h,t,q[N],dep[N],f[N][K],G[N],NXT[N],V[N];
ll d[N],ans[N];
struct E{int x,y,w;}a[M>>1];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void addedge(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
inline void add(int x,int y){deg[y]++;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline void addtree(int x,int y){V[++ed]=y;NXT[ed]=G[x];G[x]=ed;}
struct PI{
  ll x;int y;
  PI(){}
  PI(ll _x,int _y){x=_x,y=_y;}
  inline PI operator+(PI b){return x<=b.x?PI(x,y):b;}
}val[262145];
void build(int x,int a,int b){
  val[x]=PI(inf,a);
  if(a==b)return;
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
inline void change(int x,int a,int b,int c,ll d){
  if(a==b){val[x].x=d;return;}
  int mid=(a+b)>>1;
  c<=mid?change(x<<1,a,mid,c,d):change(x<<1|1,mid+1,b,c,d);
  val[x]=val[x<<1]+val[x<<1|1];
}
inline int lca(int x,int y){
  int i;
  if(dep[x]<dep[y])i=x,x=y,y=i;
  for(i=K-1;~i;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];
  if(x==y)return x;
  for(i=K-1;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
  return f[x][0];
}
void dfs(int x){
  for(int i=G[x];i;i=NXT[i])dfs(V[i]),size[x]+=size[V[i]];
  sum[id[x]]=size[x];
}
int main(){
  read(n),read(m);
  for(i=1;i<=m;i++){
    read(a[i].x),read(a[i].y),read(a[i].w);
    addedge(a[i].x,a[i].y,a[i].w);
    addedge(a[i].y,a[i].x,a[i].w);
  }
  read(S);
  for(i=1;i<=n;i++)d[i]=inf;
  build(1,1,n),change(1,1,n,S,d[S]=0);
  while(val[1].x<inf)for(change(1,1,n,x=val[1].y,inf),i=g[x];i;i=nxt[i])if(d[x]+w[i]<d[v[i]])change(1,1,n,v[i],d[v[i]]=d[x]+w[i]);
  for(ed=0,i=1;i<=n;i++)g[i]=0,size[i]=d[i]<inf;
  for(cnt=n,i=1;i<=m;i++){
    if(d[a[i].x]+a[i].w==d[a[i].y])id[++cnt]=i,add(a[i].x,cnt),add(cnt,a[i].y);
    if(d[a[i].y]+a[i].w==d[a[i].x])id[++cnt]=i,add(a[i].y,cnt),add(cnt,a[i].x);
  }
  for(cnt++,i=1;i<cnt;i++)if(!deg[i])add(cnt,i);
  q[h=t=1]=cnt,ed=0;
  while(h<=t){
    x=q[h++];
    if(f[x][0])addtree(f[x][0],x);
    for(dep[x]=dep[f[x][0]]+1,i=1;i<K;i++)f[x][i]=f[f[x][i-1]][i-1];
    for(i=g[x];i;i=nxt[i]){
      if(!f[v[i]][0])f[v[i]][0]=x;else f[v[i]][0]=lca(f[v[i]][0],x);
      if(!(--deg[v[i]]))q[++t]=v[i];
    }
  }
  dfs(cnt);
  for(i=1;i<=m;i++)ans[a[i].x]+=sum[i],ans[a[i].y]+=sum[i];
  for(i=1;i<=n;i++)printf("%lld\n",ans[i]);
  return 0;
}

  

posted @ 2015-07-27 19:26  Claris  阅读(516)  评论(0编辑  收藏  举报