[bzoj4538][Hnoi2016]网络

本文针对BZOJ4538问题提供了一种解决方案,利用线段树和LCA查询来处理网络系统中的数据交互请求,通过加入、删除有权值的链并询问不过特定点的链的最大权值。

来自FallDream的博客,未经允许,请勿转载,谢谢。


一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:1.  在某两个服务器之间出现一条新的数据交互请求;2.  某个数据交互结束请求;3.  某个服务器出现故障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。

就是要支持加入/删除一条有权值的链,询问不过一个点的链的权值最大值

n<=10^5 m<=2*10^5

 

如果树剖的话,可以把区间取反,就等于是包含一个点的线段的权值最大值了 但是那样的话脑补一下可以发现是3个log的 还容易炸空间(我并不知道那些人是怎么过的)

然后貌似有种做法比较靠谱,就是线段树维护权值区间的所有链的交,询问时候在线段树上二分,配合O(1)的lca查询的话可以做到O(nlogn)复杂度,倍增求lca的话两个log,就已经可以过啦。

然后我的做法是直接整体二分,然后每次判断每个询问的答案大于/小于二分的值。

把大于二分值的操作都拿出来,变成整条链加/减1,询问一个点的权值。如果一个点的权值等于现在存在的链的数量,那么显然答案小等于二分值,否则答案是大于的。

链加/单点查,我们求出lca配合dfs序就变成了单点改,区间查,用线段树可以轻松实现。

复杂度nlog^2n

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define MN 200000
#define MD 17
#define N 131072
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

int n,m,head[MN+5],nl[MN+5],nr[MN+5],dn,cnt,T[N*2+5],q[MN+5],q1[MN+5],q2[MN+5];
int top1,top2,fa[MD+1][MN+5],num,l[MN+5],tot=1,Ans[MN+5],dep[MN+5];
struct edge{int to,next,w;}e[MN*2+5];
struct data{int kind,x,y,z,w,ad;}s[MN+5];

inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
}

void Pre(int x,int f)
{
    nl[x]=++dn;fa[0][x]=f;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f) dep[e[i].to]=dep[x]+1,Pre(e[i].to,x);
    nr[x]=dn;
}

int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j)
        if(k&1) x=fa[j][x];
    if(x==y) return x;
    for(int i=MD;~i;--i)
        if(fa[i][x]!=fa[i][y])
            x=fa[i][x],y=fa[i][y];
    return fa[0][x];
}

void Modify(int x,int ad)
{
    T[x+=N]+=ad;
    for(x>>=1;x;x>>=1) T[x]=T[x<<1]+T[x<<1|1];
}

int Query(int l,int r)
{
    int sum=0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) sum+=T[l+1];
        if( r&1) sum+=T[r-1];
    }
    return sum;
}

void Solve(int l,int r,int lt,int rt)
{
    if(l>r) return;
    if(lt==rt)
    {
        for(int i=l;i<=r;++i)
            if(s[q[i]].kind) Ans[q[i]]=lt;
        return;
    }
    int mid=lt+rt>>1,sum=0;top1=top2=0;
    for(int i=l;i<=r;++i)
        if(s[q[i]].kind)
        {
            if(Query(nl[s[q[i]].x],nr[s[q[i]].x])==sum) q1[++top1]=q[i];
            else q2[++top2]=q[i];
        }
        else
        {
            if(s[q[i]].w>mid)
            {
                sum+=s[q[i]].ad;
                Modify(nl[s[q[i]].x],s[q[i]].ad);
                Modify(nl[s[q[i]].y],s[q[i]].ad);
                Modify(nl[s[q[i]].z],-s[q[i]].ad);
                if(s[q[i]].z!=1) Modify(nl[fa[0][s[q[i]].z]],-s[q[i]].ad);
                q2[++top2]=q[i];
            }
            else q1[++top1]=q[i];
        }
    for(int i=l;i<=r;++i)
        if(s[q[i]].kind==0&&s[q[i]].w>mid)
        {
            Modify(nl[s[q[i]].x],-s[q[i]].ad);
            Modify(nl[s[q[i]].y],-s[q[i]].ad);
            Modify(nl[s[q[i]].z],s[q[i]].ad);
            if(s[q[i]].z!=1) Modify(nl[fa[0][s[q[i]].z]],s[q[i]].ad);
        }
    for(int i=1;i<=top1;++i) q[l+i-1]=q1[i];
    for(int i=1;i<=top2;++i) q[l+top1+i-1]=q2[i];
    int pre=top1;Solve(l,l+top1-1,lt,mid);Solve(l+pre,r,mid+1,rt);
}

int main()
{
    n=read();m=read();
    for(int i=1;i<n;++i) ins(read(),read());
    Pre(1,0);l[++num]=-1;
    for(int i=1;i<=MD;++i)
        for(int j=1;j<=n;++j)
            fa[i][j]=fa[i-1][fa[i-1][j]];
    for(int i=1;i<=m;++i)
    {
        int op=read(); q[i]=i;
        if(op==0) s[i].x=read(),s[i].y=read(),s[i].z=lca(s[i].x,s[i].y),s[i].w=l[++num]=read(),s[i].ad=1;
        if(op==1) s[i]=s[read()],s[i].ad=-1;
        if(op==2) s[i].kind=1,s[i].x=read();
    }
    sort(l+1,l+num+1);
    for(int i=2;i<=num;++i) if(l[i]!=l[i-1]) l[++tot]=l[i];
    for(int i=1;i<=m;++i) if(!s[i].kind) s[i].w=lower_bound(l+1,l+tot+1,s[i].w)-l;
    Solve(1,m,1,tot);
    for(int i=1;i<=m;++i)
        if(s[i].kind) printf("%d\n",l[Ans[i]]);
    return 0;
}

转载于:https://www.cnblogs.com/FallDream/p/bzoj4538.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值