题目链接 http://codeforces.com/problemset/problem/342/E
题目大意:一棵树上有红色节点和蓝色节点。。初始时节点1为红色节点 然后两种操作 将一个蓝色节点涂成红色节点 操作2 求蓝色节点到红色节点的最短距离
题目分析:倍增算法求lca+bfs bfs求红色节点到蓝色节点的最短距离 然后每进行100次的操作 bfs一次。。然后套倍增lca的模板就行
#include<stdio.h> #include<string.h> #include<algorithm> #include<cmath> #include<queue> #include<string> #include<iostream> #define N 110000 #define CC(x,y) memset(x,y,sizeof(x)) #define inf 0x7ffffff #define ll long long #define eps 1e-6 #define M 110000 #define POW 18 using namespace std; vector<int>g[N],f; int p[N][18],fa[N],i,j,k,m,n,x,y,z,dis[N],d[N],vis[N]; queue<int>q; void DFS(int u,int fa) { d[u]=d[fa]+1; p[u][0]=fa; for(int i=1;i<POW;i++) p[u][i]=p[p[u][i-1]][i-1]; int sz=g[u].size(); for(int i=0;i<sz;i++) { int v=g[u][i]; if(v==fa) continue; DFS(v,u); } } int lca(int a,int b ){ if(d[a]>d[b]) a^= b, b^= a, a^= b; if(d[a]<d[b]){ int del = d[b]-d[a]; for( int i = 0; i < POW; i++ ) if(del&(1<<i)) b=p[b][i]; } if(a!=b){ for(int i=POW-1;i>= 0; i-- ) if( p[a][i] != p[b][i] ) a=p[a][i],b=p[b][i]; a = p[a][0], b = p[b][0]; } return a; } void LCA(int n) { d[1]=0; DFS(1,1); } void bfs() { CC(vis,0); while (!q.empty())q.pop(); for (i=0;i<f.size();i++) q.push(f[i]),dis[f[i]]=0,vis[f[i]]=1; while (!q.empty()) { int x=q.front();q.pop();vis[x]=0; for (int j=0;j<g[x].size();j++) { int y=g[x][j]; if (dis[y]==-1||dis[y]>dis[x]+1) { dis[y]=dis[x]+1; if (vis[y]==0) q.push(y),vis[y]=1; } } } f.clear(); } int main() { freopen("in.txt","r",stdin); scanf("%d%d",&n,&m); for (i=1;i<n;i++) { scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } LCA(n); CC(dis,-1);dis[1]=0; f.clear(); f.push_back(1); bfs(); int t,v; for (int i=1;i<=m;i++) { scanf("%d%d",&t,&v); //printf("%d %d\n",t,v); if (t==1) f.push_back(v); else { int p=dis[v]; for (int j=0;j<f.size();j++) p=min(p,d[v]+d[f[j]]-2*d[lca(v,f[j])]); printf("%d\n",p); } if (i%100==0) bfs(); } return 0; }