Aizu 2450 Do use segment tree LCT

本文介绍了一种使用树状结构处理复杂查询的方法,包括修改树上路径节点权重及求路径上节点权重的最大连续子序列和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Do use segment tree

Time Limit : 2 sec, Memory Limit : 256000 KB

Do use segment tree

Given a tree with n (1n200,000) nodes and a list of q (1q100,000) queries, process the queries in order and output a value for each output query. The given tree is connected and each node on the tree has a weight wi (−10,000wi10,000).

Each query consists of a number ti (ti=1,2), which indicates the type of the query , and three numbersaibi and ci (1ai,bin,10,000ci10,000). Depending on the query type, process one of the followings:

  • (ti=1: modification query) Change the weights of all nodes on the shortest path between ai and bi(both inclusive) to ci.

  • (ti=2: output query) First, create a list of weights on the shortest path between ai and bi (both inclusive) in order. After that, output the maximum sum of a non-empty continuous subsequence of the weights on the list. ci is ignored for output queries.

Input

The first line contains two integers n and q. On the second line, there are n integers which indicate w1,w2, ... , wn.

Each of the following n1 lines consists of two integers si and ei (1si,ein), which means that there is an edge between si and ei.

Finally the following q lines give the list of queries, each of which contains four integers in the format described above. Queries must be processed one by one from top to bottom.

Output

For each output query, output the maximum sum in one line.

Sample Input 1

3 4
1 2 3
1 2
2 3
2 1 3 0
1 2 2 -4
2 1 3 0
2 2 2 0

Output for the Sample Input 1

6
3
-4

Sample Input 2

7 5
-8 5 5 5 5 5 5
1 2
2 3
1 4
4 5
1 6
6 7
2 3 7 0
2 5 2 0
2 4 3 0
1 1 1 -1
2 3 7 0

Output for the Sample Input 2

12
10
10
19

Sample Input 3

21 30
10 0 -10 -8 5 -5 -4 -3 1 -2 8 -1 -7 2 7 6 -9 -6 3 4 9
10 3
3 2
3 12
12 4
4 13
4 9
10 21
21 1
1 11
11 14
1 15
10 6
6 17
6 16
6 5
5 18
5 19
10 7
10 8
8 20
1 1 21 -10
1 3 19 10
2 1 13 0
1 4 18 8
1 5 17 -5
2 16 7 0
1 6 16 5
1 7 15 4
2 4 20 0
1 8 14 3
1 9 13 -1
2 9 18 0
1 10 12 2
1 11 11 -8
2 21 15 0
1 12 10 1
1 13 9 7
2 6 14 0
1 14 8 -2
1 15 7 -7
2 10 2 0
1 16 6 -6
1 17 5 9
2 12 17 0
1 18 4 6
1 19 3 -3
2 11 8 0
1 20 2 -4
1 21 1 -9
2 5 19 0

Output for the Sample Input 3

20
9
29
27
10
12
1
18
-2
-3




#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
#define maxn 500007
#define inf  1000000000
#define ll int

struct Node{
    Node *fa,*ch[2];
    bool rev,root;
    int val,w,size;
    int ls,rs,al,ans;

};
Node pool[maxn];
Node *nil,*tree[maxn];
int cnt = 0;
void init(){
    cnt = 1;
    nil = tree[0] = pool;
    nil->ch[0] = nil->ch[1] = nil;
    nil->val = -inf;
    nil->size = 0;
    nil->ls=nil->rs=nil->al=nil->ans=-inf;
}
Node *newnode(int w,Node *f){
    pool[cnt].fa = f;
    pool[cnt].ch[0]=pool[cnt].ch[1]=nil;
    pool[cnt].rev = false;
    pool[cnt].root = true;
    pool[cnt].val = -inf;
    pool[cnt].ls=pool[cnt].rs=pool[cnt].al=pool[cnt].ans=w;
    pool[cnt].w = w;
    pool[cnt].size=1;
    return &pool[cnt++];
}
//左右子树反转******真正把结点变为根
void update_rev(Node *x){
    if(x == nil) return ;
    x->rev = !x->rev;
    swap(x->ch[0],x->ch[1]);
}
void update(Node*x);
//splay下推信息******
void pushdown(Node *x){
    if(x == nil) return ;
    if(x->rev != false){
        update_rev(x->ch[0]);
        update_rev(x->ch[1]);
        x->rev = false;
        update(x);
    }
    if(x->val != -inf){
        x->w = x->val;
        x->ch[0]->val = x->val;
        x->ch[1]->val = x->val;
        update(x->ch[0]);
        update(x->ch[1]);
        x->val = -inf;
    }
}
//splay向上更新信息******
void update(Node *x){
    if(x == nil) return ;
    x->size = x->ch[0]->size + x->ch[1]->size + 1;
    if(x->val != -inf){
        if(x->val >= 0){
            x->ans = x->al = x->rs = x->ls = x->size * x->val;
        }
        else {
            x->ans = x->rs = x->ls = x->val;
            x->al = x->size*x->val;
        }
        return ;
    }
    Node lc=*x->ch[0],rc=*x->ch[1];
    if(lc.rev) swap(lc.ls,lc.rs);
    if(rc.rev) swap(rc.ls,rc.rs);
    x->ans = x->al = x-> ls = x->rs = x->w;
    if(x->ch[0] != nil){
        x->ans = max(x->ans,lc.ans);
        x->ans = max(x->ans,x->ls+lc.rs);
        x->rs = max(x->rs,x->al+lc.rs);
        x->ls = max(lc.ls,lc.al+x->ls);
        x->al += lc.al;
    }
    if(x->ch[1] != nil){
        x->ans = max(x->ans,rc.ans);
        x->ans = max(x->ans,x->rs+rc.ls);
        x->rs = max(rc.rs,rc.al+x->rs);
        x->ls = max(x->ls,x->al+rc.ls);
        x->al += rc.al;
    }
}

//splay在root-->x的路径下推信息******
void push(Node *x){
    if(!x->root) push(x->fa);
    pushdown(x);
}
//将结点x旋转至splay中父亲的位置******
void rotate(Node *x){
    Node *f = x->fa, *ff = f->fa;
    int t = (f->ch[1] == x);
    if(f->root)
        x->root = true, f->root = false;
    else ff->ch[ff->ch[1] == f] = x;
    x->fa = ff;
    f->ch[t] = x->ch[t^1];
    x->ch[t^1]->fa = f;
    x->ch[t^1] = f;
    f->fa = x;
    update(f);
}
//将结点x旋转至x所在splay的根位置******
void splay(Node *x){
    push(x);
    Node *f, *ff;
    while(!x->root){
        f = x->fa,ff = f->fa;
        if(!f->root)
            if((ff->ch[1]==f)&&(f->ch[1] == x)) rotate(f);
            else rotate(x);
        rotate(x);
    }
    update(x);
}
//将x到树根的路径并成一条path******
Node *access(Node *x){
    Node *y = nil,*z;
    while(x != nil){
        splay(x);
        x->ch[1]->root = true;
        (x->ch[1] = y)->root = false;
        update(x);
        y = x;
        x = x->fa;
    }
    return y;
}
//将结点x变成树根******
void be_root(Node *x){
    access(x);
    splay(x);
    update_rev(x);
}
//将x连接到结点f上******
void link(Node *x, Node *f){
    be_root(x);
    x->fa = f;
}

int main(){
    int n,q,s,t,l,r;
    Node*x,*y,*z;
    while(scanf("%d%d",&n,&q)!=EOF){
        init();
        for(int i =1;i <= n; i++){
            scanf("%d",&s);
            tree[i] = newnode(s,nil);
        }
        for(int i = 1;i < n; i++){
            scanf("%d%d",&l,&r);
            link(tree[l],tree[r]);
        }
        while(q--){
            scanf("%d%d%d%d",&t,&l,&r,&s);
            if(t==1){
                be_root(tree[l]);
                x = access(tree[r]);
                x->val = s;
                update(x);
            }
            else {
                be_root(tree[l]);
                x = access(tree[r]);
                printf("%d\n",x->ans);
            }
        }
    }
    return 0;
}


1、内容概要: (1)数据结构设计:定义了包含头像、昵称、消息类型、时间、内容、未读计数的消息对象模型 (2)界面展示: a.支持文本、图片、视频三种消息类型的差异化显示 b.未读消息数字气泡提示 c.时间显示(精确到分钟 / 天前) d.交互功能:点击消息行弹出包含消息内容的操作菜单 e.空状态处理:无消息时显示占位提示 2、适用人群 (1)微信小程序开发初学者 (2)希望学习小程序 UI 组件实现的前端开发者 (3)需要快速搭建消息中心模块的开发者 (4)对微信小程序数据绑定、条件渲染机制不熟悉的人员 3、使用场景及目标 (1)社交类小程序消息中心 (2)应用通知系统 (3)订阅消息展示 (4)多平台账号聚合消息流 (5)提供可复用的消息列表 UI 组件代码 (6)展示微信小程序基础开发技术的实际应用 (7)演示如何处理列表数据渲染、条件判断、事件绑定 (8)帮助开发者快速实现具有现代感的消息界面 4、其他说明 (1)代码特点: 采用 MVVM 模式,数据与视图分离 使用微信官方推荐的组件化开发方式 完整实现了从数据定义到视图渲染的全流程 (2)扩展建议: 增加消息分类标签(如 "已读 / 未读"、"重要 / 普通") 实现消息滑动删除功能 添加消息搜索筛选能力 增加消息分组折叠展示 (3)注意事项: 图片资源路径需根据实际项目结构调整 实际项目中建议使用真实接口数据替代静态数据 未读计数应与消息状态管理系统联动 建议添加消息点击后的已读状态更新逻辑 (4)技术价值: 清晰展示了 WXML 模板语法的使用 演示了微信小程序事件处理机制 提供了列表渲染性能优化的基础框架 可作为微信小程序 UI 组件库的基础组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值