给一棵树,有两种操作:
1 将a->b路径上的点权值改为c;
2 求a->b路径上的最大连续区间和。
思路:树链剖分。通过不断合并区间,维护区间最大左区间和、最大右区间和、区间最大连续和、区间和即可。
//#pragma comment(linker, "/STACK:10240000000,10240000000")
#include<iostream>
#include<stdio.h>
#include<math.h>
#include <string>
#include<string.h>
#include<map>
#include<queue>
#include<set>
#include<utility>
#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std;
#define eps 1e-8
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define ll long long int
#define mod 1000000007
//#define maxn 200005
#define maxm 1000005
const int maxn=200100;
int ma(int a,int b){return a>b?a:b;}
struct Ed{
int to,next;
}edge[maxn*4];
int head[maxn],pos;
int top[maxn];
int fa[maxn];
int deep[maxn];
int num[maxn];
int p[maxn];
int fp[maxn];
int d,tot;
int son[maxn];
void addedge(int u,int v){
edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
/*dfs和build_tree函数为将树映射到线段树上的初始化函数*/
void dfs(int u) {
deep[u] = d;
num[u] = 1;
son[u] = 0;
d++;
for (int i = head[u]; ~i; i = edge[i].next) {
if (edge[i].to != fa[u]) {
fa[edge[i].to] = u;
dfs(edge[i].to);
num[u] += num[edge[i].to];
if (son[u] == 0 || num[edge[i].to] > num[son[u]]) son[u] = edge[i].to;
}
}
d--;
}
void build_tree(int u, int tp) {
p[u] = pos++; top[u] = tp;
if (son[u] > 0) build_tree(son[u], tp);
for (int i = head[u]; ~i; i = edge[i].next) {
if (edge[i].to != fa[u] && edge[i].to != son[u])
build_tree(edge[i].to, edge[i].to);
}
}
void init(){
tot=0;pos=0;
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
}
struct node{
int l,r,ml,mr,ms,k,v,s;//k为覆盖标记
}tree[maxn*4];
int a[maxn],b[maxn];
node max_node(node ls,node rs){//求两个区间合并后的信息,
node ans; //最大左连续值,最大右连续值和区间最大连续值h和区间和
ans.k=0;
ans.l=ls.l;ans.r=rs.r;
ans.ml=ma(ls.ml,ls.s+rs.ml);
ans.mr=ma(rs.mr,rs.s+ls.mr);
ans.s=ls.s+rs.s;
ans.ms=ma(ls.ms,ma(rs.ms,ls.mr+rs.ml));
return ans;
}
void build(int i,int l,int r){
tree[i].l=l;tree[i].r=r;
tree[i].k=0;
if(l==r) {
tree[i].s=tree[i].ml=tree[i].mr=tree[i].ms=b[l];
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)|1,mid+1,r);
tree[i]=max_node(tree[i*2],tree[i*2+1]);
}
void push_down(int i){
int ls=i*2;
int rs=i*2+1;
if(tree[i].k){
tree[ls].k=tree[rs].k=1;
tree[ls].v=tree[rs].v=tree[i].v;
tree[ls].s=(tree[ls].r-tree[ls].l+1)*tree[i].v;
tree[rs].s=(tree[rs].r-tree[rs].l+1)*tree[i].v;
if(tree[i].v>=0){
tree[ls].ml=tree[ls].mr=tree[ls].ms=tree[ls].s;
tree[rs].ml=tree[rs].mr=tree[rs].ms=tree[rs].s;
}
else{
tree[ls].ml=tree[ls].mr=tree[ls].ms=tree[i].v;
tree[rs].ml=tree[rs].mr=tree[rs].ms=tree[i].v;
}
}
tree[i].k=0;
}
void update(int i,int l,int r,int val){
if(tree[i].l==l&&tree[i].r==r){
tree[i].k=1;
tree[i].v=val;
tree[i].s=val*(r-l+1);
if(val>0) {
tree[i].ml=tree[i].mr=tree[i].ms=tree[i].s;
}
else{
tree[i].ml=tree[i].mr=tree[i].ms=val;
}
return;
}
push_down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(mid>=r) update(i<<1,l,r,val);
else if(l>mid) update((i<<1)|1,l,r,val);
else{
update(i<<1,l,mid,val);
update((i<<1)|1,mid+1,r,val);
}
tree[i]=max_node(tree[i*2],tree[i*2+1]);
}
void change(int u,int v,int val){
int f1=top[u],f2=top[v];
while(f1!=f2){
if(deep[f1]<deep[f2]){
swap(u,v);
swap(f1,f2);
}
update(1,p[f1],p[u],val);
u=fa[f1];f1=top[u];
}
if(deep[u]>deep[v]) {
swap(u,v);
}
update(1,p[u],p[v],val);
}
node query(int i,int l,int r){
if(tree[i].l==l&&tree[i].r==r){
return tree[i];
}
push_down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(mid>=r) return query(i<<1,l,r);
else if(l>mid) return query((i<<1)|1,l,r);
else{
node ls=query(i<<1,l,mid);
node rs=query((i<<1)|1,mid+1,r);
return max_node(ls,rs);
}
}
int query(int u,int v){//求路径上的最大连续区间,不断合并被剖分成的区间维护信息集合,注意合并方向
int f1=top[u],f2=top[v];
int k1=0,k2=0;
node ans1,ans2;
while(f1!=f2){
/* if(deep[f1]<deep[f2]){
swap(f1,f2);
swap(u,v);
}
update(1,p[f1],p[u],val);
u=fa[f1];f1=top[u];*/
if(deep[f1]>=deep[f2]){
node aa=query(1,p[f1],p[u]);
u=fa[f1];f1=top[u];
if(k1) ans1=max_node(aa,ans1);
else { k1=1; ans1=aa;
}
}
else{
node aa=query(1,p[f2],p[v]);
v=fa[f2];f2=top[v];
if(k2) ans2=max_node(aa,ans2);
else { k2=1; ans2=aa;
}
}
}
// if(deep[u]>deep[v]) swap(u,v);
// update(1,p[u],p[v],val);
if(deep[u]<=deep[v]){
node aa=query(1,p[u],p[v]);
if(k2) ans2=max_node(aa,ans2);
else { k2=1; ans2=aa;
}
}
else{
node aa=query(1,p[v],p[u]);
if(k1) ans1=max_node(aa,ans1);
else { k1=1; ans1=aa;
}
}
if(k1&&k2){
swap(ans1.ml,ans1.mr);
node aa=max_node(ans1,ans2);
return aa.ms;
}
else if(k1) return ans1.ms;
else return ans2.ms;
}
int n,q,u,v,z,op;
int main()
{
// rd(t);
while(~rd2(n,q)){
//rd(n);
init();
for(int i=1;i<=n;i++){
rd(a[i]);
}
for(int i=1;i<n;i++){
rd2(u,v);
addedge(u,v);
addedge(v,u);
}
// dfs1(1,0,0);
// getpos(1,1);
d=1;
dfs(1);
build_tree(1,1);
for(int i=1;i<=n;i++){
b[p[i]]=a[i];
}
build(1,0,n-1);
for(int i=1;i<=q;i++){
rd2(op,u);rd2(v,z);
if(op==1) change(u,v,z);
else{
printf("%d\n",query(u,v));
}
}
}
return 0;
}