题意:给出一棵树,最开始结点1为红色,其他点为蓝色。有两种操作,一种是把某个结点变为红色,另一种是查询某个点与这个点最近的红色结点的距离。
思路:这题感觉纠结了好久。。。其实利用分块的方法非常简单粗暴,用mind[u]表示距离u最近的红点的距离,把第一个操作分块,每次执行第一个操作时把这个点存下来,当点的数量到达sqrt(m)时,利用bfs更新点到最近红点的距离。查询时,结果为保存的点和查询点的距离的和mind[u]的较小值。
代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct Edge
{
int v,next;
Edge(){}
Edge(int v,int next):v(v),next(next){}
}edges[maxn<<1];
int head[maxn],nEdge;
int d[maxn],mind[maxn],pa[maxn][22];
vector<int>rednode;
void AddEdges(int u,int v)
{
edges[++nEdge]=Edge(v,head[u]);
head[u]=nEdge;
edges[++nEdge]=Edge(u,head[v]);
head[v]=nEdge;
}
void Init()
{
memset(head,0xff,sizeof(head));
memset(pa,0,sizeof(pa));
memset(mind,0x3f,sizeof(mind));
d[1]=0;nEdge=-1;
}
void dfs(int u,int fa)
{
for(int k=head[u];k!=-1;k=edges[k].next)
{
int v=edges[k].v;
if(v==fa) continue;
pa[v][0]=u;
d[v]=d[u]+1;
dfs(v,u);
}
}
void lca_Init(int n)
{
for(int i=1;i<=20;++i)
for(int j=1;j<=n;++j)
pa[j][i]=pa[pa[j][i-1]][i-1];
}
int Lca(int x,int y)
{
if(x==y) return x;
if(d[x]>d[y]) swap(x,y);
for(int i=20;i>=0;--i)
if(d[pa[y][i]]>d[x]) y=pa[y][i];
if(pa[y][0]==x) return x;
if(d[y]>d[x]) y=pa[y][0];
for(int i=20;i>=0;--i)
{
if(pa[y][i]!=pa[x][i])
{
y=pa[y][i];
x=pa[x][i];
}
}
return pa[x][0];
}
void bfs()
{
queue<int>q;
int sz=rednode.size();
for(int i=0;i<sz;++i)
{
int v=rednode[i];
q.push(v);mind[v]=0;
}
while(!q.empty())
{
int u=q.front();q.pop();
for(int k=head[u];k!=-1;k=edges[k].next)
{
int v=edges[k].v;
if(mind[v]>mind[u]+1)
{
mind[v]=mind[u]+1;
q.push(v);
}
}
}
rednode.clear();
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,u,v;
scanf("%d%d",&n,&m);
Init();
for(int i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
AddEdges(u,v);
}
dfs(1,-1);
lca_Init(n);
rednode.clear();
rednode.push_back(1);
bfs();
int size=sqrt(m)+1,cnt=0;
while(m--)
{
scanf("%d%d",&u,&v);
if(u==1)
{
rednode.push_back(v);
cnt++;
if(cnt==size)
{
bfs();
cnt=0;
}
}
else
{
int sz=rednode.size();
int ans=mind[v];
for(int i=0;i<sz;++i)
{
u=rednode[i];
int anc=Lca(u,v);
ans=min(ans,d[u]+d[v]-2*d[anc]);
}
printf("%d\n",ans);
}
}
return 0;
}
该博客介绍了如何使用分块技术解决一道关于树结构的问题。题目涉及将树上的节点颜色变化及查询最近红色节点距离的操作。作者提出,通过维护每个节点到最近红色节点的距离,并在红色节点数量达到平方根(m)时更新,可以有效处理此类问题。查询时,取保存的节点与目标节点距离和当前节点到最近红色节点距离的最小值作为答案。
253

被折叠的 条评论
为什么被折叠?



