HDU 4916 Count on the path 树形dp
题意:给出一棵树,f(a,b)表示不在a,b路径上的最小点的编号。q组询问,每次给出u,v,询问f(u,v)
题解:显然如果两个点的lca不是1,那么答案就是1。可以把1号节点当作根做一次dfs,然后去掉这个点,形成了一片森林。在森林中,预处理出\(mn\_id[i]\)表示i子树内最小点的编号:\(mn\_id[u]=min(u,mn\_id[v])\)
第二次dfs处理出\(dp[i]\)表示不在i到新根节点的路上的最小点编号。
\(dp[u]=min(mn\_id[v],去掉u后形成的树中最小的mn_id)\)
怎么得到u的兄弟中最小的mn_id呢,其实就是在递归之前记录一下u的父亲fa的所有儿子的mn_id中排名前两小的值,当mn_id[u]==mn1时就传入mn2,否则传入mn1
查询的时候,先用并查集的方法检查a和b是否在一个连通块,在的话显然lca不等于1,答案为1。
如果不在同一个连通块,说明lca为1,那么就要在它们两棵子树中取一个最小值,即取\(min(dp[a],dp[b])\)。
但是除了这两个连通块外,还要考虑图中其他连通块的最小值。所以可以在事先处理出来mn_id[rt]最小的前三个值。最后输出答案的时,先取dp[a],dp[b]中的最小值,再和u和v所属连通块以外的,属于前3小的连通块的mn_id[rt]取min。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,q,pos,head[N];
struct edge
{
int to,next;
}e[N<<1];
void add(int x,int y)
{
e[++pos].next=head[x];
e[pos].to=y;
head[x]=pos;
}
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
void update(int &x,int y){
if(x>y) x=y;
}
struct node
{
int d,bel;
bool operator < (const node &x)const{
return d<x.d;
}
bool operator != (const int &x)const{
return bel!=x;
}
void clear(){d=1e9;}
}b[4];
int fa[N],bel[N];
int mn_id[N],dp[N];
void dfs(int u,int f)
{
mn_id[u]=u;
fa[u]=f;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;if(v==f)continue;
if(u!=1) bel[v]=bel[u];
dfs(v,u);
update(mn_id[u],mn_id[v]);
}
}
void dfs1(int u,int res)
{
dp[u]=res;
int mn1=1e9,mn2=1e9;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;if(v==fa[u])continue;
update(dp[u],mn_id[v]);
if(mn_id[v]<mn1) mn2=mn1,mn1=mn_id[v];
else if(mn_id[v]<mn2) mn2=mn_id[v];
}
for(int i=head[u];i;i=e[i].next)
{
int nxt;
int v=e[i].to;if(v==fa[u])continue;
if(mn1==mn_id[v]) nxt=mn2;
else nxt=mn1;
dfs1(v,min(res,nxt));
}
}
void init()
{
dp[1]=1e9;pos=0;
for(int i=1;i<=n;i++)head[i]=0,bel[i]=i;
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
init();
for(int i=1;i<n;i++)
{
int a,b;scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs(1,0);
for(int i=1;i<=3;i++) b[i].clear();
for(int i=head[1];i;i=e[i].next)
{
int v=e[i].to;
dfs1(v,1e9);
node P;P.d=mn_id[v],P.bel=v;
if(P<b[1]) b[3]=b[2],b[2]=b[1],b[1]=P;
else if(P<b[2]) b[3]=b[2],b[2]=P;
else if(P<b[3]) b[3]=P;
}
int lastans=0;
while(q--)
{
int u,v;scanf("%d%d",&u,&v);
u=u^lastans,v=v^lastans;
if(u==v&&u==1)
{
puts("2");
continue;
}
if(bel[u]==bel[v])
{
puts("1");
lastans=1;
continue;
}
lastans=min(dp[u],dp[v]);
u=bel[u],v=bel[v];
if(b[1]!=u&&b[1]!=v) update(lastans,b[1].d);
else if(b[2]!=u&&b[2]!=v) update(lastans,b[2].d);
else if(b[3]!=u&&b[3]!=v) update(lastans,b[3].d);
printf("%d\n",lastans);
}
}
return 0;
}

浙公网安备 33010602011771号