给出一棵有 N N N 个点的树,每个点的编号为 1 ∼ N 1\sim N 1∼N,其中 1 1 1 号点为这棵树的根。每条边有一个权值,初始时第 i i i 条边的权值为 w i w_i wi。两个点之间的距离为以这两个点为端点的简单路径上的所有边的权值和。
现在对这棵树有 M M M 次操作,每次操作的格式如下:
1 i k
:将第
i
i
i 条边的权值修改为
k
k
k;
2 x y
:询问以
x
x
x 为根的子树中一点
u
u
u 与以
y
y
y 为根的子树中一点
v
v
v 间的最大距离;
3 x a b
:询问以
x
x
x 为根的子树中一点
u
u
u 与以
a
a
a,
b
b
b 为端点的简单路径上一点
v
v
v 间的最大距离。
第 1 1 1 行包含两个正整数 N , M N,M N,M,分别表示树的结点数和操作次数;
第 2 2 2 行至第 N N N 行,第 i + 1 i+1 i+1 行包含三个整数 u i , v i , w i u_i,v_i,w_i ui,vi,wi,表示第 i i i 条边连接节点 u i u_i ui 与节点 v i v_i vi,初始时权值为 w i w_i wi;
第 N + 1 N+1 N+1 行至第 N + M N+M N+M 行,每行表示一次操作,格式见题目描述。
对于每次询问操作,输出一个整数表示答案。
样例输入
5 5
1 2 1
1 3 2
2 4 3
2 5 4
2 1 2
3 2 4 3
1 1 2
2 4 3
3 2 5 3
样例输出
7
7
7
8
测试点编号 | N , M ≤ N,M \leq N,M≤ | w i ≤ w_i \leq wi≤ | o p t = opt= opt= | 特殊性质 |
---|---|---|---|---|
1 1 1 | 500 500 500 | 1000 1000 1000 | 2 , 3 2,3 2,3 | 无 无 无 |
2 2 2 | 500 500 500 | 1000 1000 1000 | 1 , 2 , 3 1,2,3 1,2,3 | 无 无 无 |
3 3 3 | 2000 2000 2000 | 1000 1000 1000 | 1 , 2 1,2 1,2 | 无 无 无 |
4 4 4 | 2000 2000 2000 | 1000 1000 1000 | 1 , 3 1,3 1,3 | C C C |
5 5 5 | 2000 2000 2000 | 1 0 9 10^9 109 | 2 , 3 2,3 2,3 | A A A |
6 6 6 | 2000 2000 2000 | 1 0 9 10^9 109 | 1 , 2 , 3 1,2,3 1,2,3 | 无 无 无 |
7 7 7 | 5 × 1 0 4 5 \times 10^4 5×104 | 1000 1000 1000 | 2 2 2 | B B B |
8 8 8 | 5 × 1 0 4 5 \times 10^4 5×104 | 1000 1000 1000 | 3 3 3 | A A A |
9 9 9 | 5 × 1 0 4 5 \times 10^4 5×104 | 1 0 9 10^9 109 | 1 , 2 , 3 1,2,3 1,2,3 | A A A |
10 10 10 | 5 × 1 0 4 5 \times 10^4 5×104 | 1 0 9 10^9 109 | 1 , 2 , 3 1,2,3 1,2,3 | B , C B,C B,C |
11 ∼ 12 11\sim 12 11∼12 | 5 × 1 0 4 5 \times 10^4 5×104 | 1 0 9 10^9 109 | 1 , 2 , 3 1,2,3 1,2,3 | 无 无 无 |
13 13 13 | 1 0 5 10^5 105 | 1 0 9 10^9 109 | 1 , 2 1,2 1,2 | B B B |
14 14 14 | 1 0 5 10^5 105 | 1 0 9 10^9 109 | 1 , 3 1,3 1,3 | C C C |
15 15 15 | 1 0 5 10^5 105 | 1 0 9 10^9 109 | 2 , 3 2,3 2,3 | 无 无 无 |
16 16 16 | 1 0 5 10^5 105 | 1 0 9 10^9 109 | 1 , 2 , 3 1,2,3 1,2,3 | A A A |
17 ∼ 20 17\sim 20 17∼20 | 1 0 5 10^5 105 | 1 0 9 10^9 109 | 1 , 2 , 3 1,2,3 1,2,3 | 无 无 无 |
对于所有测试点, 1 ≤ N , M ≤ 100000 1 \leq N,M \leq 100000 1≤N,M≤100000, 1 ≤ w i , k ≤ 1 0 9 1 \leq w_i,k \leq 10^9 1≤wi,k≤109。
说明
o p t opt opt 一栏表示该测试点会出现的询问种类,与输入中给出的每次询问的第一个数字相对应。
特殊性质一栏中,
A A A 表示该测试点给出的树是一条链;
B B B 表示对于所有 2 2 2操作,都有 x = y x=y x=y;
C C C 表示对于所有 3 3 3操作,都有 a = b a=b a=b。
题解:
首先,发现若求出树上前缀和,可以把路径转化成
d
[
x
]
+
d
[
y
]
−
2
×
d
[
l
c
a
]
d[x]+d[y]-2\times d[lca]
d[x]+d[y]−2×d[lca]
这时,考虑把树转化成区间,但又得支持链的操作,所以用
E
T
T
ETT
ETT 序
假设已经建出
E
T
T
ETT
ETT 序,我们发现对于
x
x
x 和
y
y
y 的路径,可以转化成
d
[
x
]
+
d
[
y
]
−
2
×
d
[
z
]
d[x]+d[y]-2\times d[z]
d[x]+d[y]−2×d[z] 且
z
z
z 是区间
[
x
,
y
]
[x,y]
[x,y] 中
d
e
p
dep
dep 最小的点,这启发我们用线段树维护。
对于
x
(
x
≤
l
)
x(x \leq l)
x(x≤l) 到
[
l
,
r
]
[l,r]
[l,r] 的询问,发现
y
y
y 属于
[
l
,
r
]
[l,r]
[l,r],
z
z
z 可能在
[
x
,
l
]
[x,l]
[x,l] 中也可能在
[
l
,
y
]
[l,y]
[l,y]中,我们只需要用线段树维护区间
d
e
p
dep
dep 最小的点,
d
[
y
]
−
d
[
z
]
d[y]-d[z]
d[y]−d[z] 最大的
y
y
y,以及最终的答案。
对于其他情况同理。
#include<bits/stdc++.h>
#define N 100005
#define A p<<1
#define B p<<1|1
typedef long long ll;
using namespace std;
const ll inf=1e15;
inline int read(){
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
return x*f;
}
int tot=1,head[N],ver[N<<1],nex[N<<1],dfs_num,st[N],ed[N],q[N<<1];
ll edge[N<<1];
inline void add(int x,int y,int z){
nex[++tot]=head[x];head[x]=tot;ver[tot]=y;edge[tot]=z;
}
int dep[N];
ll d[N];
void dfs(int x,int las){
st[x]=++dfs_num;q[dfs_num]=x;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==las)continue;
dep[y]=dep[x]+1;
d[y]=d[x]+edge[i];
dfs(y,x);
q[++dfs_num]=x;
}
ed[x]=dfs_num;
}
struct seg{
int l,r;
ll maxn[4],lazy,minn[2];
inline void init(){
memset(maxn,0,sizeof(maxn));lazy=0;
minn[0]=minn[1]=inf;
}
}t[N<<3];/*
inline void up(int p){
t[p].maxn[0]=max(t[A].maxn[0],t[B].maxn[0]);
t[p].maxn[1]=max(t[B].maxn[1],t[B].maxn[0]-2*t[A].minn[1]);
t[p].maxn[2]=max(t[A].maxn[2],t[A].maxn[0]-2*t[B].minn[1]);
t[p].maxn[3]=max(t[A].maxn[0]+t[B].maxn[1],t[A].maxn[2]+t[B].maxn[0]);
t[p].minn[0]=min(t[A].minn[0],t[B].minn[0]);
if(t[p].minn[0]==t[A].minn[0])t[p].minn[1]=t[A].minn[1];
if(t[p].minn[0]==t[B].minn[0])t[p].minn[1]=t[B].minn[1];
}*/
inline seg up(seg a,seg b){
seg x;x.l=a.l,x.r=b.r,x.lazy=0;
x.maxn[0]=max(a.maxn[0],b.maxn[0]);
x.maxn[1]=max(b.maxn[1],b.maxn[0]-2*a.minn[1]);x.maxn[1]=max(x.maxn[1],a.maxn[1]);
x.maxn[2]=max(a.maxn[2],a.maxn[0]-2*b.minn[1]);x.maxn[2]=max(x.maxn[2],b.maxn[2]);
x.maxn[3]=max(a.maxn[0]+b.maxn[1],a.maxn[2]+b.maxn[0]);x.maxn[3]=max(x.maxn[3],max(a.maxn[3],b.maxn[3]));
x.minn[0]=min(a.minn[0],b.minn[0]);
if(x.minn[0]==a.minn[0])x.minn[1]=a.minn[1];
if(x.minn[0]==b.minn[0])x.minn[1]=b.minn[1];
return x;
}
inline void push(int p,ll z){
t[p].maxn[0]+=z;t[p].maxn[1]-=z;t[p].maxn[2]-=z;t[p].minn[1]+=z;
t[p].lazy+=z;
}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;t[p].init();
if(l==r){
for(int i=0;i<3;++i)t[p].maxn[i]=d[q[l]];
for(int i=1;i<=2;++i)t[p].maxn[i]-=2*d[q[l]];
t[p].minn[0]=dep[q[l]],t[p].minn[1]=d[q[l]];
t[p].maxn[3]=0;
return ;
}
int mid=(l+r)>>1;
build(A,l,mid);build(B,mid+1,r);
t[p]=up(t[A],t[B]);
//cout<<l<<" "<<r<<" "<<t[p].maxn[0]<<endl;
}
inline void wo(int p){
if(t[p].lazy!=0){
push(A,t[p].lazy);push(B,t[p].lazy);t[p].lazy=0;
}
}
void change(int p,int l,int r,ll val){
if(t[p].l>=l&&t[p].r<=r){
push(p,val);
return ;
}
wo(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)change(A,l,r,val);
if(r>mid)change(B,l,r,val);
t[p]=up(t[A],t[B]);
}
seg ask(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
return t[p];
}
wo(p);
int mid=(t[p].l+t[p].r)>>1;
// cout<<t[p].l<<" "<<t[p].r<<" "<<l<<" "<<r<<endl;
if(r<=mid)return ask(A,l,r);
if(l>mid)return ask(B,l,r);
return up(ask(A,l,r),ask(B,l,r));
}
inline ll work(int xl,int xr,int yl,int yr){
if(xl>xr||yl>yr)return 0;
//cout<<xl<<" "<<xr<<" "<<yl<<" "<<yr<<endl;
if(xl==yl&&xr==yr){
//cout<<ask(1,xl,xr).maxn[3]<<endl;
return ask(1,xl,xr).maxn[3];
}
ll ans=0;
seg le=ask(1,xl,xr),re=ask(1,yl,yr);
ans=max(le.maxn[2]+re.maxn[0],le.maxn[0]+re.maxn[1]);
//cout<<le.maxn[2]<<" "<<re.maxn[0]<<endl;
if(xr<yl-1){
ans=max(ans,le.maxn[0]+re.maxn[0]-2*ask(1,xr+1,yl-1).minn[1]);
}
//cout<<ans<<endl;
return ans;
}
inline ll quer(int xl,int xr,int yl,int yr){
if(xl>yl)swap(xl,yl),swap(xr,yr);
ll ans=0;
if(xr<yl-1){
ans=work(xl,xr,yl,yr);
}else{
if(xl==yl&&xr<yr)swap(xl,yl),swap(xr,yr);
ans=max(work(xl,yl-1,yl,yr),work(yl,yr,yl,yr));
ans=max(ans,work(yl,yr,yr+1,xr));
}
return ans;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("tree.out","w",stdout);
int n=read(),m=read();
for(int i=1;i<n;++i){
int x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
}
dep[1]=1;
dfs(1,0);
//for(int j=1;j<=n;++j)cout<<d[j]<<" ";cout<<endl;
build(1,1,dfs_num);
/* for(int i=1;i<=dfs_num;++i){
cout<<q[i]<<" ";
}*/
// cout<<endl;
// cout<<endl;
while(m--){
int op=read();
if(op==1){
int i=read()*2;ll k=read();
int x=ver[i],y=ver[i^1];
if(dep[x]>dep[y])swap(x,y);
//cout<<st[y]<<" "<<ed[y]<<endl;
change(1,st[y],ed[y],k-edge[i]);
edge[i]=edge[i^1]=k;
}
if(op==2){
int x=read(),y=read();
ll ans=quer(st[x],ed[x],st[y],ed[y]);
printf("%lld\n",ans);
}
if(op==3){
int x=read(),a=read(),b=read();
ll ans=max(quer(st[x],ed[x],st[a],st[a]),quer(st[x],ed[x],st[b],st[b]));
//node l=quer(st[x],ed[x],st[a],st[a]),r=quer(st[x],ed[x],st[b],st[b]);
//cout<<r.maxn[0]<<" "<<r.maxn[
printf("%lld\n",ans);
}
}
return 0;
}/*
5 4
1 2 70
1 3 53
1 4 21
3 5 2
1 1 41
1 4 51
1 1 41
3 2 1 2
*/