Do use segment tree 树链剖分,按顺序剖分

一棵树,支持两种操作,1是将a到b路径上点的权值改为c,求a到b路径上的最大连续字段和。

维护最大字段和,最大前缀和,最大后缀和。

树练剖分,需要按顺序求出链的所有段,向上合并。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<ostream>
#include<istream>
#include<algorithm>
#include<queue>
#include<string>
#include<cmath>
#include<set>
#include<bitset>
#include<map>
#include<stack>
#include<vector>
#define fi first
#define se second
#define ll long long
#define pii pair<int,int>
#define inf (1<<30)
#define eps 1e-8
#define pb push_back
using namespace std;
const int maxn=200005;
int son[maxn],top[maxn],dep[maxn],fa[maxn],siz[maxn],id[maxn],fid[maxn];
int sz;
vector<int>g[maxn];
int val[maxn];
int n,q;
struct Node
{
    ll ls,rs,sum,ans;
    Node(ll a,ll b,ll c,ll d):ls(a),rs(b),sum(c),ans(d){}
    Node(){}
}node[maxn<<2];
ll add[maxn<<2];
void dfs(int u,int f)
{
    siz[u]=1;
    son[u]=0;
    for(int i=0;i<g[u].size();i++) {
        if(g[u][i]==f)
            continue;
        int v=g[u][i];
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs(v,u);
        if(siz[v]>siz[son[u]]) son[u]=v;
        siz[u]+=siz[v];
    }
}
void build(int u,int w)
{
    id[u]=++sz;
    fid[sz]=u;
    top[u]=w;
    if(son[u]) build(son[u],w);
    for(int i=0;i<g[u].size();i++) {
        int v=g[u][i];
        if(v==fa[u]) continue;
        if(v!=son[u]) build(v,v);
    }
}
void T()
{
    int rt=(n+1)/2;
    sz=0;
    dep[rt]=0;
    fa[rt]=0;
    dfs(rt,0);
    build(rt,rt);
}
void pushUp(int rt)
{
    node[rt].ans=max(node[rt<<1].ans,node[rt<<1|1].ans);
    node[rt].ans=max(node[rt].ans,node[rt<<1].rs+node[rt<<1|1].ls);
    node[rt].sum=node[rt<<1].sum+node[rt<<1|1].sum;
    node[rt].ls=max(node[rt<<1].ls,node[rt<<1].sum+node[rt<<1|1].ls);
    node[rt].rs=max(node[rt<<1|1].rs,node[rt<<1|1].sum+node[rt<<1].rs);
}
void change(int l,int r,int rt,int c)
{
    if(c>=0) {
        node[rt].sum=(ll)(r-l+1)*c;
        node[rt].ans=node[rt].ls=node[rt].rs=node[rt].sum;
    }
    else {
        node[rt].sum=(ll)(r-l+1)*c;
        node[rt].ls=node[rt].rs=node[rt].ans=c;
    }
}
void pushDown(int l,int r,int rt)
{
    if(add[rt]==inf) return;
    int m=((l+r)>>1);
    change(l,m,rt<<1,add[rt]);
    change(m+1,r,rt<<1|1,add[rt]);
    add[rt<<1]=add[rt<<1|1]=add[rt];
    add[rt]=inf;
}
Node unite(Node u,Node v)
{
    Node p;
    p.ans=max(u.ans,v.ans);
    p.ans=max(p.ans,u.rs+v.ls);
    p.sum=u.sum+v.sum;
    p.ls=max(u.ls,u.sum+v.ls);
    p.rs=max(v.rs,v.sum+u.rs);
    return p;
}
Node query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
        return node[rt];
    pushDown(l,r,rt);
    Node ans=Node(-inf, -inf, 0, -inf);
    int m=((l+r)>>1);
    if(L<=m)
        ans=unite(ans,query(L,R,l,m,rt<<1));
    if(R>m)
        ans=unite(ans,query(L,R,m+1,r,rt<<1|1));
    return ans;
}
ll query(int u,int v)
{
    int a = top[u], b = top[v];
    Node lpath = Node(-inf , -inf, 0, -inf), rpath = Node(-inf, -inf, 0, -inf);
    while(a != b){
        if( dep[a] > dep[b]){
            Node res = query(id[a], id[u],1,n,1);
            swap(res.ls, res.rs);
            lpath = unite(lpath, res);
            u = fa[a];
            a = top[u];
        }
        else{
            Node res = query(id[b], id[v],1,n,1);
            rpath = unite(res, rpath);
            v = fa[b];
            b = top[v];
        }
    }
    Node ans;
    if( dep[u] < dep[v] ){
        ans = query(id[u], id[v],1,n,1);
    }
    else{
        ans = query(id[v], id[u],1,n,1);
        swap(ans.ls,ans.rs);
    }
    ans = unite(lpath, ans);
    ans = unite(ans, rpath);
    return ans.ans;
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&R>=r) {
        change(l,r,rt,c);
        add[rt]=c;
        return;
    }
    pushDown(l,r,rt);
    int m=((l+r)>>1);
    if(L<=m)
        update(L,R,c,l,m,rt<<1);
    if(R>m)
        update(L,R,c,m+1,r,rt<<1|1);
    pushUp(rt);
}
void update(int a,int b,int c)
{
    int f1=top[a],f2=top[b];
    while(f1!=f2) {
        if(dep[f1]<dep[f2]) {
            swap(f1,f2);
            swap(a,b);
        }
        update(id[f1],id[a],c,1,n,1);
        a=fa[f1]; f1=top[a];
    }
    if(dep[a]>dep[b]) swap(a,b);
    update(id[a],id[b],c,1,n,1);
}
void buildTree(int l,int r,int rt)
{
    add[rt]=inf;
    if(l==r) {
        int a=fid[l];
        node[rt].ls=node[rt].rs=node[rt].sum=node[rt].ans=val[a];
        return;
    }
    int m=((l+r)>>1);
    buildTree(l,m,rt<<1);
    buildTree(m+1,r,rt<<1|1);
    pushUp(rt);
}
int main()
{
    int ty;
    int a,b,c;
    while(~scanf("%d%d",&n,&q)) {
        for(int i=1;i<=n;i++) {
            scanf("%d",&val[i]);
            g[i].clear();
        }
        for(int i=0;i<n-1;i++) {
            scanf("%d%d",&a,&b);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        T();
        buildTree(1,n,1);
        for(int i=0;i<q;i++) {
            scanf("%d%d%d%d",&ty,&a,&b,&c);
            if(ty==1) {
                update(a,b,c);
            }
            else {
                printf("%lld\n",query(a,b));
            }
        }
    }
    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值