[AGC002D] Stamp Rally 整体二分+并查集

本文探讨了在一个由n个点和m条边组成的简单无向连通图中,如何通过并查集和二分查找算法解决路径覆盖特定数量顶点的问题,旨在寻找路径上经过的边的最大编号最小化方案。

Description

给你一个n个点m个条边构成的简单无向连通图,有Q组询问,每次询问从两个点x,y走出两条路径,使这两条路径覆盖z个点,求得一种方案使得路径上经过的变的最大编号最小。

Input

第一行两个整数n,m,如题目所述

接下来m行,每行两个整数x,y描述一条边

接下来一个整数Q,如题目所述

接下来Q行,每行三个整数x,y,z,如题目描述

Output

Q行,每行一个正整数,如题目描述

Sample Input

5 6
2 3
4 5
1 2
1 3
1 4
1 5
6
2 4 3
2 4 4
2 4 5
1 3 3
1 3 4
1 3 5

Sample Output

1
2
3
1
5
5

HINT

n,m,q≤10^5

Sol

考虑单组询问的做法,显然可以二分答案,然后用并查集把所有小于等于的边合并,判断是否可行即可。

这里每组询问互相独立,我们上整体二分即可。

如果把整体二分写成BFS形式的话不用还原并查集啦,而且好写得多,具体地,我们建出类似线段树的东西,然后求出每个线段的mid,按照顺序并查集合并,如果当前i和这一层其中一个mid相等就判断这个节点vector中的元素是否达标并下传即可。

每一层要清空并查集。

Code

#include <bits/stdc++.h>
using namespace std;
struct que{int x,y,z;}q[100005];vector<int>v[800050];
int n,m,Q,x,y,now=1,U[100005],V[100005],cnt[100005],ans[100005],mid[800050],l[800050],r[800050],f[100005],sz[100005];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void bud(int x,int L,int R){l[x]=L;r[x]=R;mid[x]=(L+R)>>1;if(L==R) return;bud(x*2,L,mid[x]);bud(x*2+1,mid[x]+1,R);}
int main()
{
    scanf("%d%d",&n,&m);memset(ans,0x3f,sizeof(ans));
    for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),U[i]=x,V[i]=y;
    scanf("%d",&Q);bud(1,1,m);
    for(int i=1;i<=Q;i++) scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z),v[1].push_back(i);
    for(int gg=m*4;gg;gg>>=1)
    {
        for(int i=1;i<=n;i++) f[i]=i,sz[i]=1,cnt[i]=0;
        for(int i=1;i<=m;i++)
        {
            if((x=find(V[i]))!=(y=find(U[i]))) f[y]=f[x],sz[x]+=sz[y];
            if(i==mid[now]) for(int j=0;j<v[now].size();j++)
            {
                int a=find(q[v[now][j]].x),b=find(q[v[now][j]].y);
                cnt[v[now][j]]=(a==b)?sz[a]:sz[a]+sz[b];
                if(cnt[v[now][j]]<q[v[now][j]].z) v[now*2+1].push_back(v[now][j]);
                else v[now*2].push_back(v[now][j]),ans[v[now][j]]=mid[now];
            }
            if(i==mid[now]||!mid[now]) now++;
        }
    }
    for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}

转载于:https://www.cnblogs.com/CK6100LGEV2/p/9483704.html

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值