poj 3237 线段树+树链剖分

本文介绍了一种结合树链剖分和线段树的数据结构算法,用于解决涉及树形结构上的路径操作问题,如修改边权值、翻转路径权值及查询最大权值等。
Tree
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 3587 Accepted: 1004

Description

You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

CHANGE i vChange the weight of the ith edge to v
NEGATE a bNegate the weight of every edge on the path from a to b
QUERY a bFind the maximum weight of edges on the path from a to b

Input

The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers ab and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

Output

For each “QUERY” instruction, output the result on a separate line.

Sample Input

1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output

1
3

Source

题意:给一棵树,三种操作。将第i条边的权值改为v,将a到b的路径上的边的权值全部取反,求a到b路径上边的权值的最大值。

思路:明显的树链剖分,加上线段树的操作。因为有取反的操作所以每个区间要记录最大值和最小值。查询两点间的路径时,用求公共祖先的方式去求。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#define N 20005
#define inf 0x3fffffff
using namespace std;
struct line
{
    int x,y,w;
}ed[N];
struct node
{
    int u,v,w,next;
}bian[N*2];
struct pp
{
    int x,y,ma,mi,p;
}a[N*3];
int e,id;
int sz[N],dep[N],head[N],top[N],son[N],father[N],ti[N];
int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}
void add(int u,int v,int w)
{
    bian[e].u=u;
    bian[e].v=v;
    bian[e].w=w;
    bian[e].next=head[u];
    head[u]=e++;
}
void dfs1(int u,int fa)
{
    int i,v;
    sz[u]=1; dep[u]=dep[fa]+1; son[u]=0;  father[u]=fa;
    for(i=head[u];i!=-1;i=bian[i].next)
    {
        v=bian[i].v;
        if(v==fa) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v])
            son[u]=v;
    }
}
void dfs2(int u,int fa)
{
    int i,v;
    top[u]=fa;
    ti[u]=id++;
    if(son[u]!=0)
        dfs2(son[u],fa);
    for(i=head[u];i!=-1;i=bian[i].next)
    {
        v=bian[i].v;
        if(v==son[u]||v==father[u])
            continue;
        dfs2(v,v);
    }
}
void pushdown(int t)
{
    int temp=t<<1;
    a[t].ma=max(a[temp].ma,a[temp+1].ma);
    a[t].mi=min(a[temp].mi,a[temp+1].mi);
}
void build(int t ,int x,int y)
{
    a[t].x=x; a[t].y=y;  a[t].ma=a[t].mi=a[t].p=0;
    if(x==y)  return;
    int mid=(x+y)>>1,temp=t<<1;
    build(temp,x,mid);
    build(temp+1,mid+1,y);
}
void find(int t)
{
    int temp=t<<1;
    if(a[t].p)
    {
        a[temp].ma=-a[temp].ma; a[temp].mi=-a[temp].mi;
        swap(a[temp].ma,a[temp].mi);
        a[temp+1].ma=-a[temp+1].ma; a[temp+1].mi=-a[temp+1].mi;
        swap(a[temp+1].ma,a[temp+1].mi);
        a[temp].p^=1;
        a[temp+1].p^=1;
        a[t].p=0;
    }
}
int query(int t,int x,int y)//查询线段树中[x,y]的最大值
{
    int ma;
    if(a[t].x==x&&a[t].y==y)
        return a[t].ma;
    int mid=(a[t].x+a[t].y)>>1,temp=t<<1;
    find(t);
    if(y<=mid)
        return query(temp,x,y);
    else if(x>mid)
        return query(temp+1,x,y);
    else
        return max(query(temp,x,mid),query(temp+1,mid+1,y));
}
int lca(int x,int y)//返回最大值
{
    int ans;
    ans=-inf;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        ans=max(ans,query(1,ti[top[x]],ti[x]));
        x=father[top[x]];
    }
    if(dep[x]>dep[y])
        swap(x,y);
    if(x!=y)
        ans=max(ans,query(1,ti[x]+1,ti[y]));
    return ans;
}
void update(int t ,int x,int w)//更新线段树的第x个值为w
{
    if(a[t].x==a[t].y)
    {
       a[t].ma=a[t].mi=w;
       a[t].p=0;
        return;
    }
    int mid=(a[t].x+a[t].y)>>1,temp=t<<1;
    find(t);
    if(x<=mid)
        update(temp,x,w);
    else
        update(temp+1,x,w);
    pushdown(t);
}
void reupdate(int t,int x,int y)//更新线段树的区间[x,y]取反
{
    if(a[t].x==x&&a[t].y==y)
    {
        a[t].ma=-a[t].ma; a[t].mi=-a[t].mi;
        swap(a[t].ma,a[t].mi);
        a[t].p^=1;
        return ;
    }
    int mid=(a[t].x+a[t].y)>>1,temp=t<<1;
    find(t);
    if(y<=mid)
        reupdate(temp,x,y);
    else if(x>mid)
        reupdate(temp+1,x,y);
    else
    {
        reupdate(temp,x,mid);
        reupdate(temp+1,mid+1,y);
    }
    pushdown(t);
}
void relca(int x,int y)//把x到y路径上的值都取反
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        reupdate(1,ti[top[x]],ti[x]);
        x=father[top[x]];
    }
    if(dep[x]>dep[y])
        swap(x,y);
    if(x!=y)
        reupdate(1,ti[x]+1,ti[y]);
}
int main()
{
    int t,i,x,y,v,n;
    char str[100];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        e=0;  memset(head,-1,sizeof(head));
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].w);
            add(ed[i].x,ed[i].y,ed[i].w);
            add(ed[i].y,ed[i].x,ed[i].w);
        }
        dep[1]=0;  id=1;  sz[0]=0;
        dfs1(1,1);
        dfs2(1,1);
     //for(i=1;i<=n;i++)
       // printf("i=%d size=%d top=%d father=%d son=%d ti=%d dep=%d\n",i,sz[i],top[i],father[i],son[i],ti[i],dep[i]);
        build(1,1,n);
        for(i=1;i<n;i++)
        {
            if(dep[ed[i].x]<dep[ed[i].y])
                swap(ed[i].x,ed[i].y);
            update(1,ti[ed[i].x],ed[i].w);
        }
        while(scanf("%s",str),strcmp(str,"DONE")!=0)
        {
            if(str[0]=='Q')
            {
                scanf("%d%d",&x,&y);
                printf("%d\n",lca(x,y));//查询x->y路径上边权的最大值
            }
            else if(str[0]=='N')
            {
                scanf("%d%d",&x,&y);
                relca(x,y);
            }
            else if(str[0]=='C')
            {
                scanf("%d%d",&i,&v);//改变第i条边的值为v
                update(1,ti[ed[i].x],v);
            }
        }
    }
    return 0;
}


内容概要:本文系统介绍了算术优化算法(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、付费专栏及课程。

余额充值