HDU 5266 pog loves szh III 题解
作者:互联网
错误示范:倍增+暴力
开始看到这题时限 6s 本来想着来一发暴力区间倍增 LCA,后来发现是多测之后自然凉凉,准保 T 飞。
然而没有 T,acc 上 RE(ReCoders),HDU WA。
正解:树剖+线段树
维护区间你想到了什么?当然是线段树啊!
分别考虑线段树的 build 和 query 操作。
- build:递归,然后 pushup 维护区间的 LCA 信息,此处倍增向上要麻烦(更何况我不擅长)一些,所以用树剖求 LCA。
- query:跟普通的线段树没什么太大区别,但是注意特判求 LCA 函数返回的 -1(所以稍微麻烦了一点)。
然后就非常简单了。
求 LCA 的 x=fa[top[x]];
被我写进了 swap 的大括号里面,然后我虚空 debug 了 10min,警钟长鸣。
Code
//5266. pog loves szh III
#include <bits/stdc++.h>
using namespace std;
const int MAXN=300005;
/***********树链剖分***********/
struct Edge
{
int to,nxt;
}e[MAXN<<1];
int n,m,cnt,head[MAXN],dep[MAXN],siz[MAXN],top[MAXN],fa[MAXN],son[MAXN];
void addedge(int x,int y)
{
e[++cnt].nxt=head[x];
head[x]=cnt;
e[cnt].to=y;
return;
}
void DFS1(int u,int f)
{
int v;
dep[u]=dep[f]+1;
fa[u]=f;
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==f)
{
continue;
}
DFS1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])
{
son[u]=v;
}
}
return;
}
void DFS2(int u,int tp)
{
int v;
top[u]=tp;
if(!son[u])
{
return;
}
DFS2(son[u],tp);
for(int i=head[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v==fa[u]||v==son[u])
{
continue;
}
DFS2(v,v);
}
return;
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
x=fa[top[x]];
}
return dep[x]<=dep[y]?x:y;
}
/***********线段树***********/
int tr[MAXN<<2];
void pushup(int p)
{
tr[p]=LCA(tr[p<<1],tr[p<<1|1]);
return;
}
void build(int p,int l,int r)
{
int mid;
if(l==r)
{
tr[p]=l;
return;
}
mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
return;
}
int query(int p,int l,int r,const int L,const int R)
{
int mid,res1,res2;
if(L<=l&&r<=R)
{
return tr[p];
}
mid=(l+r)>>1;
res1=res2=-1;
if(L<=mid)
{
res1=query(p<<1,l,mid,L,R);
}
if(mid+1<=R)
{
res2=query(p<<1|1,mid+1,r,L,R);
}
if(~res1)
{
if(~res2)
{
return LCA(res1,res2);
}
else
{
return res1;
}
}
else
{
return res2;
}
}
/***********Main***********/
int main()
{
int u,v;
while(~scanf("%d",&n))
{
cnt=0;
memset(head,0,sizeof(head));
memset(fa,0,sizeof(fa));
memset(son,0,sizeof(son));
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
DFS1(1,0);
DFS2(1,1);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&u,&v);
printf("%d\n",query(1,1,n,u,v));
}
}
return 0;
}
/*
* HDU
* https://acm.hdu.edu.cn/showproblem.php?pid=5266
* C++20 -O0
* 2022.9.11
*/
标签:5266,HDU,int,题解,top,son,build,LCA,线段 来源: https://www.cnblogs.com/2020gyk080/p/16684079.html