给定一棵 n n n 个节点的树,边带权,需要支持五种操作:
- 将输入的第 i i i 条边权值改为 w w w
- 将 u , v u,v u,v 节点之间的边权都变为相反数
- 询问 u , v u,v u,v 节点之间边权和
- 询问 u , v u,v u,v 节点之间边权最大值
- 询问 u , v u,v u,v 节点之间边权最小值
1 ≤ n , m ≤ 2 × 1 0 5 1\le n,m \le 2\times 10^5 1≤n,m≤2×105。
调了2个多小时的题,纪念一下。树链剖分基本上都是同一个套路,所以就拿这一题详细写一下。
首先用2次 D F S DFS DFS 得到分解成链后的边(在处理的时候用儿子点存起来比较方便),之后建一个线段树维护。单点修改直接处理省去一个 t a g tag tag ,只需要存储一个 t a g tag tag 来表示是否有需要处理的相反数操作。
在遇到相反数操作时, m a x = − m i n max=-min max=−min , m i n = − m a x min=-max min=−max , s u m = − s u m sum=-sum sum=−sum 即可。对 t a g tag tag 异或1即可。
最后写一下调了2个多小时的原因,在线段树单点修改时递归参数给错了,看了几遍没看出来,血的教训!
顺便说一下,对于复杂信息上传其实可以用重载加法运算符(这里没用),这样可以省去一些代码量
#include<bits/stdc++.h>
#define ll long long
#define FOR(i,j,k) for(int i=j;i<=k;++i)
#define pb push_back
ll in(){
ll x=0,f=1;
char c;
do{
c=getchar();
if(c=='-'){
f=-1;
}
}while(c<'0' || c>'9');
while(c>='0' && c<='9'){
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return f*x;
}
struct ST_node{
int minn,maxn,sum;
int l,r,tag;
};
struct ST{
ST_node nd[800005];
int a[200005];
#define ls(p) p<<1
#define rs(p) p<<1|1
#define lr int l=nd[p].l;int r=nd[p].r
inline void add_tag(int p){
nd[p].tag=1-nd[p].tag;
std::swap(nd[p].maxn,nd[p].minn);
nd[p].maxn=-nd[p].maxn;
nd[p].minn=-nd[p].minn;
nd[p].sum=-nd[p].sum;
}
inline void push_up(int p){
nd[p].maxn=std::max(nd[ls(p)].maxn,nd[rs(p)].maxn);
nd[p].minn=std::min(nd[ls(p)].minn,nd[rs(p)].minn);
nd[p].sum=nd[ls(p)].sum+nd[rs(p)].sum;
}
void push_down(int p){
if(nd[p].tag){
add_tag(ls(p));
add_tag(rs(p));
nd[p].tag=0;
}
}
void build(int l,int r,int p){
nd[p].l=l;
nd[p].r=r;
if(l==r){
nd[p].maxn=nd[p].minn=nd[p].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls(p));
build(mid+1,r,rs(p));
push_up(p);
}
void change(int p,int q,int k){
lr;
if(l==r){
nd[p].maxn=k;nd[p].minn=k;nd[p].sum=k;
return;
}
push_down(p);
int mid=(l+r)>>1;
if(q<=mid)
change(ls(p),q,k);
if(q>mid)
change(rs(p),q,k);
push_up(p);
}
void reverse(int p,int ql,int qr){
lr;
if(ql<=l && r<=qr){
add_tag(p);
return;
}
push_down(p);
int mid=(l+r)>>1;
if(ql<=mid)
reverse(ls(p),ql,qr);
if(qr>mid)
reverse(rs(p),ql,qr);
push_up(p);
}
ST_node get_all(int p,int ql,int qr){
lr;
if(ql<=l && r<=qr){
return nd[p];
}
int mid=(l+r)>>1;
push_down(p);
ST_node gl,gr;
if(ql<=mid)
gl=get_all(ls(p),ql,qr);
else if(qr>mid)
return get_all(rs(p),ql,qr);
if(qr>mid)
gr=get_all(rs(p),ql,qr);
else
return gl;
gl.sum+=gr.sum;
gl.maxn=std::max(gl.maxn,gr.maxn);
gl.minn=std::min(gl.minn,gr.minn);
return gl;
}
}S;
struct Tree{
struct Tree_node{
int fa,son,to,top,sz,dep,val;
std::vector <int> v,w,id;
}nd[200005];
int b[200005],cnt;
void DFS1(int x){
nd[x].dep=nd[nd[x].fa].dep+1;
nd[x].sz=1;
int mx=-1;
for(int i=0;i<nd[x].v.size();++i){
int y=nd[x].v[i];
if(y==nd[x].fa)
continue;
nd[y].fa=x;
nd[y].val=nd[x].w[i];
b[nd[x].id[i]]=y;
DFS1(y);
nd[x].sz+=nd[y].sz;
if(nd[y].sz>mx){
mx=nd[y].sz;
nd[x].son=y;
}
}
}
void DFS2(int x,int top){
cnt++;
nd[x].top=top;
nd[x].to=cnt;
S.a[cnt]=nd[x].val;
if(nd[x].son)
DFS2(nd[x].son,top);
for(int i=0;i<nd[x].v.size();++i){
int y=nd[x].v[i];
if(y==nd[x].fa || y==nd[x].son)
continue;
DFS2(y,y);
}
}
void Rev(int x,int y){
while(nd[x].top!=nd[y].top){
if(nd[nd[x].top].dep<nd[nd[y].top].dep)
std::swap(x,y);
S.reverse(1,nd[nd[x].top].to,nd[x].to);
x=nd[nd[x].top].fa;
}
if(nd[x].dep>nd[y].dep)
std::swap(x,y);
if(x!=y){
S.reverse(1,nd[x].to+1,nd[y].to);
}
}
ST_node Query(int x,int y){
ST_node ret;
ret.maxn=-100000000;
ret.minn=100000000;
ret.sum=0;
while(nd[x].top!=nd[y].top){
if(nd[nd[x].top].dep<nd[nd[y].top].dep)
std::swap(x,y);
ST_node st_node=S.get_all(1,nd[nd[x].top].to,nd[x].to);
ret.maxn=std::max(ret.maxn,st_node.maxn);
ret.minn=std::min(ret.minn,st_node.minn);
ret.sum+=st_node.sum;
x=nd[nd[x].top].fa;
}
if(nd[x].dep>nd[y].dep)
std::swap(x,y);
if(x!=y){
ST_node st_node=S.get_all(1,nd[x].to+1,nd[y].to);
ret.maxn=std::max(ret.maxn,st_node.maxn);
ret.minn=std::min(ret.minn,st_node.minn);
ret.sum+=st_node.sum;
}
return ret;
}
}T;
int n,m;
int main(){
n=in();
FOR(i,1,n-1){
int u=in(),v=in(),w=in();
T.nd[u].id.pb(i); T.nd[v].id.pb(i);
T.nd[u].v.pb(v); T.nd[v].v.pb(u);
T.nd[u].w.pb(w); T.nd[v].w.pb(w);
}
T.cnt=-1;
T.DFS1(0);
T.DFS2(0,0);
S.build(1,n-1,1);
m=in();
while(m){
m--;
char c;
do{
c=getchar();
}while(c!='S' && c!='M' && c!='N' && c!='C');
switch(c){
case('C'):{
int i=in(),w=in();
S.change(1,T.nd[T.b[i]].to,w);
break;
}
case('N'):{
int u=in(),v=in();
T.Rev(u,v);
break;
}
case('S'):{
int u=in(),v=in();
printf("%d\n",T.Query(u,v).sum);
break;
}
case('M'):{
if(getchar()=='A'){
int u=in(),v=in();
printf("%d\n",T.Query(u,v).maxn);
}
else{
int u=in(),v=in();
printf("%d\n",T.Query(u,v).minn);
}
break;
}
}
}
}