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;
}
posted @ 2014-03-02 15:31  forever97  阅读(159)  评论(0编辑  收藏  举报