HDU 2874 Connections between cities

题解:求树上最短路,所以直接LCA:

倍增求LCA:

#include <cstdio>

int f[10010][18];

int s[10010],d[10010],from[10010];

int g[10010],nxt[20010],edv[20010],edw[20010],cnt;

bool vis[10010];

int q,a,b,e,n,m,i,j,x,y,tmp;

void swap(int &a,int &b){int c=a;a=b;b=c;}

void add(int u,int v,int w){

    edv[++cnt]=v;edw[cnt]=w;

    nxt[cnt]=g[u];g[u]=cnt;

}

void dfs(int x,int fa,int fr,int sum){

    from[x]=fr;f[x][0]=fa;

    vis[x]=1;

    d[x]=d[fa]+1;

    s[x]=sum;

    for(int i=g[x];i;i=nxt[i])if(!vis[edv[i]])dfs(edv[i],x,fr,sum+edw[i]);

}

int lca(int x,int y){

	if(x==y)return x;

	if(d[x]<d[y])swap(x,y);

	for(int i=17;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];

	if(x==y)return x;

	for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];

	return f[x][0];

}

int main(){

    while(~scanf("%d%d%d",&n,&m,&q)){

        for(i=0;i<=10000;i++)

         for(j=0;j<18;j++)

           f[i][j]=0;

        for(i=0;i<=n;i++)vis[i]=from[i]=s[i]=d[i]=g[i]=0;

        cnt=0;

        for(i=0;i<m;i++){

            scanf("%d%d%d",&a,&b,&e);

            add(a,b,e);add(b,a,e);

        }

        for(i=1;i<=n;i++)if(!vis[i])dfs(i,0,i,0);

        for(j=1;j<18;j++)

        for(i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];

        for(i=0;i<q;i++){

            scanf("%d%d",&x,&y);

            if(from[x]!=from[y])puts("Not connected");

            else printf("%d\n",s[x]+s[y]-2*s[lca(x,y)]);

        }

    }

    return 0;

}

动态树:

#include <cstdio>

#include <cstring>

#define N 20010

using namespace std;

int f[N],son[N][2],sum[N],data[N],a[N];bool rev[N];

inline void swap(int&a,int&b){int c=a;a=b;b=c;}

inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}

inline void pb(int x){

  if(rev[x]){

    swap(son[x][0],son[x][1]);

    rev[son[x][0]]^=1;rev[son[x][1]]^=1;

    rev[x]=0;

  }

}

inline void up(int x){

  sum[x]=data[x]+sum[son[x][0]]+sum[son[x][1]];

}

inline void rotate(int x){

  int y=f[x];int w=(son[y][1]==x);

  son[y][w]=son[x][w^1];

  if(son[x][w^1])f[son[x][w^1]]=y;

  if(f[y]){

    int z=f[y];

    if(son[z][0]==y)son[z][0]=x;

    if(son[z][1]==y)son[z][1]=x;

  }

  f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);

}

inline void splay(int x){

  int s=1,i=x,y;a[1]=i;

  while(!isroot(i))a[++s]=i=f[i];

  while(s)pb(a[s--]);

  while(!isroot(x)){

    y=f[x];

    if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}

    rotate(x);

  }

  up(x);

}

inline void access(int x){

  for(int y=0;x;y=x,x=f[x]){

    splay(x);

    son[x][1]=y;

    up(x);

  }

}

inline int root(int x){

  access(x);

  splay(x);

  while(son[x][0])x=son[x][0];

  return x;

}

inline void makeroot(int x){

  access(x);

  splay(x);

  rev[x]^=1;

}

inline void link(int x,int y){

  makeroot(x);

  f[x]=y;

  access(x);

}

inline int getsum(int x,int y){

  makeroot(x);

  access(y);

  splay(x);

  return sum[x];

}

inline void read(int&a){

  char ch;while(!((ch=getchar())>='0')&&(ch<='9'));

  a=ch-'0';while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0';

}

int n,m,x,y,c,q;

inline void solve(){

  memset(f,0,sizeof f);

  memset(son,0,sizeof son);

  memset(sum,0,sizeof sum);

  memset(data,0,sizeof data);

  memset(rev,0,sizeof rev);

  read(m);read(q);

  for(int i=1;i<=m;i++){

    read(x);read(y);read(c);

    sum[n+i]=data[n+i]=c;

    link(x,n+i);link(n+i,y);

  }

  while(q--){

    read(x);read(y);

    if(root(x)!=root(y))puts("Not connected");

    else printf("%d\n",getsum(x,y));

  }

}

int main(){

  while(~scanf("%d",&n))solve();

  return 0;

}

你可能感兴趣的:(Connection)