AtCoder Beginner Contest 350 G - Mediator
链接:https://atcoder.jp/contests/abc350/tasks/abc350_g
大致题意:给出n个点,q个询问
1号询问 要求u,v之前加一条无向边 图始终是一个森林
2号询问 询问是否有一个点与u,v都相邻,若有则输出该点,若无则输出0。
询问强制在线。
思路:在题目要求的图中,满足2号询问的点只有三种情况:要么这个点是u,v的根节点;要么三者在一条链上,u是v的爷爷或者v是u的爷爷。
那么在这道题中,加边操作会影响原先的两个点的父子关系,那么在每次加边时都需要重新对图进行重构。
每次加边的时候相当于把两块部分相连,在这里可以用启发式合并的思想。我们用并查集维护每个点所在的联通块的大小,对于每次加边的两个节点所在的联通块,我们将小的那个联通块合并到大的那个。那么在每次查询的时候只需要根据父子关系得到答案即可。
#define maxn 200010
vector<int> vec[maxn];
int n,m;
int p[maxn],siz[maxn],fa[maxn];
int xx;
int find(int x)
{
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
void merge(int x,int y)
{
int a=find(x);
int b=find(y);
if(a!=b)
{
p[a]=b;
siz[b]+=siz[a];
siz[a]=0;
}
}
void dfs(int u)
{
for(auto v:vec[u])
{
if(v==fa[u]) continue;
fa[v]=u;
dfs(v);
}
}
int query(int x,int y)
{
if(fa[x]==fa[y]&&fa[x]!=0)
{
return fa[x];
}
if(fa[fa[x]]==y)
{
return fa[x];
}
if(fa[fa[y]]==x)
{
return fa[y];
}
return 0;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
p[i]=i;
siz[i]=1;
}
for(int i=1;i<=m;i++)
{
int op,u,v;
cin>>op>>u>>v;
op=1+(((op*(1+xx))%mod)%2);
u=1+(((u*(1+xx))%mod)%n);
v=1+(((v*(1+xx))%mod)%n);
if(op==2)
{
xx=query(u,v);
cout<<xx<<'\n';
continue;
}
else{
if(siz[find(u)]<siz[find(v)])
{
swap(u,v);
}
vec[u].push_back(v);
vec[v].push_back(u);
fa[v]=u;
merge(v,u);
dfs(v);
}
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!