http://codeforces.com/problemset/problem/342/E
可以假设所有红点都给定了不会再变 然后求与某个蓝点最近的红点的距离 这样直接BFS一遍就好啊
但是这里有修改 肯定不可能每改一次都跑一遍BFS 这时就要用到分块法 即每累积sqrt(n)次修改就统一大改一次 碰到查询时就先o(1)看之前大改后求得的最短距离 然后再和累积的小修改都求一下最短距离 树上最短距离就用lca
因为求lca是logn 所以可以把累积次数放小一点 防止偏沉
#include <bits/stdc++.h>
using namespace std;
struct node
{
int v;
int next;
};
node edge[400010];
int dp[200010][20];
int que[200010];
int first[200010],deep[200010],red[200010],dis[200010],book[200010];
int n,q,num,head,tail;
void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}
void dfs(int cur,int fa)
{
int i,v;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(v!=fa)
{
dp[v][0]=cur;
deep[v]=deep[cur]+1;
dfs(v,cur);
}
}
return;
}
void solve()
{
int i,j;
dp[1][0]=0;
deep[1]=1;
dfs(1,0);
for(j=1;(1<<j)<=n;j++)
{
for(i=1;i<=n;i++)
{
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
return;
}
int getlca(int u,int v)
{
int i;
if(deep[u]<deep[v]) swap(u,v);
for(i=log2(n);i>=0;i--)
{
if(deep[dp[u][i]]>=deep[v])
{
u=dp[u][i];
}
}
if(u==v) return u;
for(i=log2(n);i>=0;i--)
{
if(dp[u][i]!=dp[v][i])
{
u=dp[u][i];
v=dp[v][i];
}
}
return dp[u][0];
}
void bfs()
{
int i,u,v;
memset(book,0,sizeof(book));
for(i=head;i<=tail;i++) book[que[i]]=1;
while(head<=tail)
{
u=que[head];
head++;
for(i=first[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(book[v]==0&&dis[v]>dis[u]+1)
{
que[++tail]=v;
dis[v]=dis[u]+1,book[v]=1;
}
}
}
head=1,tail=0;
}
void init()
{
memset(dis,0x3f,sizeof(dis));
head=1,tail=0;
que[++tail]=1;
red[1]=1,dis[1]=0;
bfs();
}
int main()
{
int i,tp,u,v,lca,ans;
scanf("%d%d",&n,&q);
memset(first,-1,sizeof(first));
num=0;
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
solve();
init();
while(q--)
{
scanf("%d%d",&tp,&u);
if(tp==1)
{
if(red[u]==0)
{
que[++tail]=u;
red[u]=1,dis[u]=0;
if(tail-head+1==100) bfs();
}
}
else
{
ans=dis[u];
for(i=head;i<=tail;i++)
{
lca=getlca(u,que[i]);
ans=min(ans,deep[u]+deep[que[i]]-2*deep[lca]);
}
printf("%d\n",ans);
}
}
return 0;
}