时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
kotomi 有一棵树。树上有n个房子,编号1-n,每个房子有一个快乐值。
kotomi想知道从a房子到b房子路径上的最大快乐值或者路径山疙瘩快乐值的和。
并且kotomi可以改变任意一个房子的快乐值。
具体如下
(1) 0 a b:查询a到b路径上的最大快乐值(包含a和b)
(2) 1 a b:查询a到b路径上的所有房子快乐值的和。(包含a和b)
(3) 2 x y:将编号为x的房子的快乐值改为y。
输入描述:
多组测试数据第一行有两个整数n,q。表示有n个房子,q次操作。第二行有n个整数v1,v2...vn,表示编号为i的房子的快乐值vi接下来n-1行,每行两个整数u,v,表示编号为u和编号为v的房子之间有一条直接路径。接下来p行,每行开头一个整数(0,1或2)表述操作类型,每个操作后有两个整数。
输出描述:
对于操作为0和1的输出对应的值。
示例1
输入
6 10 2 5 9 10 36 5 1 2 1 3 1 4 2 5 2 6 0 1 4 0 1 6 1 5 6 1 3 6 1 6 3 2 3 10 1 5 3 0 4 5 2 5 100 1 5 4
输出
10 5 46 21 21 53 36 117
#include<bits/stdc++.h>
using namespace std;
const int MAX=4e4;
vector<int>e[MAX];
int a[MAX],son[MAX],siz[MAX],d[MAX],fa[MAX],tp[MAX],val[MAX],num[MAX],all;
void dfs1(int k,int f,int dep)
{
d[k]=dep; //k节点的深度
fa[k]=f; //k节点的父亲
siz[k]=1; //以k为根的子树的节点个数
son[k]=0; //记录重儿子
for(int i=0;i<e[k].size();i++)
{
if(e[k][i]==f)continue;
dfs1(e[k][i],k,dep+1);
siz[k]+=siz[e[k][i]];
if(siz[son[k]]<siz[e[k][i]])son[k]=e[k][i];//更新重儿子
}
}
void dfs2(int k,int top)
{
tp[k]=top; //k所在的链的顶端
num[k]=++all;
val[all]=a[k];
if(son[k])dfs2(son[k],top);//优先遍历重儿子
for(int i=0;i<e[k].size();i++)
{
if(e[k][i]==fa[k]||e[k][i]==son[k])continue;
dfs2(e[k][i],e[k][i]);
}
}
struct lenka
{
int l,r,ma,sum;
}A[MAX<<2];
void build(int k,int l,int r)
{
A[k].l=l,A[k].r=r;
if(l==r)
{
A[k].ma=val[l];
A[k].sum=val[l];
return;
}
build(2*k,l,(l+r)/2);
build(2*k+1,(l+r)/2+1,r);
A[k].ma=max(A[2*k].ma,A[2*k+1].ma);
A[k].sum=A[2*k].sum+A[2*k+1].sum;
}
void change(int k,int x,int y)
{
if(x==A[k].l&&x==A[k].r){A[k].ma=A[k].sum=y;return;}
if(x<=A[2*k].r)change(2*k,x,y);
else change(2*k+1,x,y);
A[k].ma=max(A[2*k].ma,A[2*k+1].ma);
A[k].sum=A[2*k].sum+A[2*k+1].sum;
}
int ask(int k,int x,int y,int tag)
{
if(x==A[k].l&&y==A[k].r)return tag?A[k].sum:A[k].ma;
if(y<=A[2*k].r)return ask(2*k,x,y,tag);
else if(x>=A[2*k+1].l)return ask(2*k+1,x,y,tag);
else
{
if(tag)return ask(2*k,x,A[2*k].r,tag)+ask(2*k+1,A[2*k+1].l,y,tag);
else return max(ask(2*k,x,A[2*k].r,tag),ask(2*k+1,A[2*k+1].l,y,tag));
}
}
long long get(int x,int y,int tag)
{
long long ans=-1e15,sum=0;
while(tp[x]!=tp[y])//逐渐向一条链上靠拢并同时更新答案
{
if(d[tp[x]]<d[tp[y]])swap(x,y);
if(tag==0)ans=max(ans,(long long)ask(1,num[tp[x]],num[x],0));
else sum+=(long long)ask(1,num[tp[x]],num[x],1);
x=fa[tp[x]];
}
if(d[x]>d[y])swap(x,y);
if(tag==0)ans=max(ans,(long long)ask(1,num[x],num[y],0));
else sum+=(long long)ask(1,num[x],num[y],1);
return tag?sum:ans;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)e[i].clear();
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
all=0;
dfs1(1,0,1);
dfs2(1,1);
build(1,1,all);
while(m--)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==0)printf("%lld\n",get(x,y,0));
else if(op==1)printf("%lld\n",get(x,y,1));
else change(1,num[x],y);
}
}
return 0;
}