一棵树,支持两种操作,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;
}