[UOJ217]奇怪的线段树

本文探讨了ZKW线段树在定位区间过程中的应用,通过优化边数和构建附加点来解决特定问题,并结合最小流算法求解。详细介绍了算法实现流程,包括节点处理、边连接及最小流计算。

如果一个节点是$0$但它子树内有$1$那么无解,否则我们只需把那些是$1$但子树内没有其他$1$的节点(这些区间是被定位的区间)都访问一遍即可

根据ZKW线段树定位区间的过程,可以发现一段(从左到右)连续的右儿子+左儿子序列确定了一个区间

所以对每个右儿子$[l,r]$,连$[0,\infty)$向$[r+1,x]$的节点,对每个左儿子$[l,r]$,连$[0,+\infty)$向$[r+1,x]$的左儿子,再对那些被定位到的点拆点连$[1,\infty)$,跑最小流即可

但这样边数太多,考虑优化,建$n$个附加点,对于左儿子$[l,r]$,从附加点$l$连向它再连向附加点$r+1$,但这样会产生左儿子连到右儿子这种不合法情况,所以对左儿子和右儿子分别建$n$个附加点即可

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int inf=2147483647;
int h[24010],nex[128010],to[128010],cap[128010],M=1,S,T;
void ins(int a,int b,int c){
	M++;
	to[M]=b;
	cap[M]=c;
	nex[M]=h[a];
	h[a]=M;
}
void add(int a,int b,int c){
	ins(a,b,c);
	ins(b,a,0);
}
int dis[24010],q[24010];
bool bfs(){
	int head,tail,x,i;
	memset(dis,-1,sizeof(dis));
	head=tail=1;
	q[1]=S;
	dis[S]=0;
	while(head<=tail){
		x=q[head++];
		for(i=h[x];i;i=nex[i]){
			if(cap[i]&&dis[to[i]]==-1){
				dis[to[i]]=dis[x]+1;
				if(to[i]==T)return 1;
				q[++tail]=to[i];
			}
		}
	}
	return 0;
}
int cur[24010];
int dfs(int x,int flow){
	if(x==T)return flow;
	int us=0,i,t;
	for(i=cur[x];i&&flow;i=nex[i]){
		if(cap[i]&&dis[to[i]]==dis[x]+1){
			t=dfs(to[i],min(flow,cap[i]));
			cap[i]-=t;
			cap[i^1]+=t;
			us+=t;
			flow-=t;
			if(cap[i])cur[x]=i;
		}
	}
	if(us==0)dis[x]=-1;
	return us;
}
int dicnic(){
	int ans=0;
	while(bfs()){
		memcpy(cur,h,sizeof(h));
		ans+=dfs(S,inf);
	}
	return ans;
}
void add(int a,int b,int l,int r){
	if(l){
		add(S,b,l);
		add(a,T,l);
	}
	if(r!=inf)r-=l;
	add(a,b,r);
}
int tS,tT;
int minflow(){
	dicnic();
	add(tT,tS,0,inf);
	return dicnic();
}
int lp[4010],rp[4010],n,N;
int build(int l,int r,int f){
	int siz=0,t,mid;
	scanf("%d",&t);
	if(l<r){
		scanf("%d",&mid);
		siz=build(l,mid,0)+build(mid+1,r,1);
	}
	if(!t&&siz)throw"OwO";
	if(t){
		add(tS,N,0,inf);
		add(N,N+1,!siz,inf);
		add(N+1,tT,0,inf);
		if(f==1){
			add(rp[l],N,0,inf);
			if(r<n){
				add(N+1,rp[r+1],0,inf);
				add(N+1,lp[r+1],0,inf);
			}
		}
		if(f==0){
			add(rp[l],N,0,inf);
			add(lp[l],N,0,inf);
			if(r<n)add(N+1,lp[r+1],0,inf);
		}
		N+=2;
	}
	return siz+t;
}
int main(){
	scanf("%d",&n);
	try{
		S=1;
		T=2;
		tS=3;
		tT=4;
		for(int i=1;i<=n;i++){
			lp[i]=i+4;
			rp[i]=i+n+4;
		}
		N=rp[n]+1;
		build(1,n,-1);
		printf("%d",minflow());
	}catch(const char*s){
		puts(s);
	}
}

转载于:https://www.cnblogs.com/jefflyy/p/9776197.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、付费专栏及课程。

余额充值