题意描述

给定一棵 个节点的树,边带权,编号 ,需要支持以下五种操作:

  1. C i w 将输入的第 条边权值改为
  2. N u v 节点之间的边权都变为相反数
  3. SUM u v 询问 节点之间边权和
  4. MAX u v 询问 节点之间边权最大值
  5. MIN u v 询问 节点之间边权最小值

保证任意时刻所有边的权值都在 内。


输入格式

第一行一个正整数 ,表示节点个数。

接下来 行,每行三个整数 ,表示 之间有一条权值为 的边,描述这棵树。

然后一行一个正整数 ,表示操作数。

接下来 行,每行表示一个操作。


输出格式

对于每一个询问操作,输出一行一个整数表示答案。


Input & Output 's examples

Input 's eg 1

3
0 1 1
1 2 2
8
SUM 0 2
MAX 0 2
N 0 1
SUM 0 2
MIN 0 2
C 1 3
SUM 0 2
MAX 0 2

Output 's eg 1

3
2
1
-1
5
3

数据范围和约定

对于的数据:


分析

养 生 题 目 警 告

题目中要求我们维护一棵树上信息,且为区间操作,很容易想到树剖维护。

但问题在于树剖只能维护点权,但本题要求维护边权。

因此,我们考虑如何把边权转为点权

容易发现,树上的一个点仅有一个父亲,且该点与其父亲之间仅有一条边相连。

因此我们可以将该点与其父亲相连边的边权转移至该点上。由于一个点只有一个父亲,因此这样的转移是唯一的。

但这样会出现一个问题:在查询时,我们会多算两节点的父亲的一条边。

因此,当两节点在同一条重链上时,左端点需要右移一位以减去多算的边。

还有就是操作的一点细节:取相反数后,原本的区间最大值会变成最小值,区间最小值会变成区间最大值。在做pushdown的时候需要特别注意。

然后是树剖版子题了……

至于代码的话,也就大约10kb,往死里写就完事了


Code[Accepted]

#include <algorithm>
#include <iostream>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include <cstdio>
#include <string>
#include <vector>
#include <cctype>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <map>
#include <set>

#define I inline
#define ll long long
#define pb push_back
#define MP make_pair
#define ull unsigned long long
#define PII pair<int , int>
#define PIL pair<int , long long>
#define PSL pair<string , long long>
#define PLL pair<long long , long long>
#define all(x) (x).begin() , (x).end()
#define copy(a , b) memcpy(a , b , sizeof(b))
#define clean(a , b) memset(a , b , sizeof(a))
#define rep(i , l , r) for (int i = (l); i <= (r); i ++)
#define per(i , r , l) for (int i = (r); i >= (l); i --)
#define PE(i , x) for(int i = head[x]; i; i = edge[i].last)
#define DEBUG(x) std :: cerr << #x << '=' << x << std :: endl

using namespace std;

const int N = 10001;
const int M = 200001;
const int HA = 998244353;
const int INF = 2147483647;
const long long INFL = 9223372036854775807;

struct Edge{
    int to , last , dis;
}edge[M << 1];

int edge_num;
int head[M << 1];

I void add_edge(int from , int to , int dis){
    edge[++ edge_num] = (Edge){to , head[from] , dis}; head[from] = edge_num;
    edge[++ edge_num] = (Edge){from , head[to] , dis}; head[to] = edge_num;
}

int dep[M] , fa[M] , son[M] , size[M] , val[M];

int dfs1(int x , int f , int deep){
    dep[x] = deep;
    fa[x] = f;
    int maxn = -1;
    PE(i , x){
        int to = edge[i].to , dis = edge[i].dis;
        if(to == f) continue;
        val[to] = dis;
        size[x] += dfs1(to , x , deep + 1);
        if(size[to] > maxn){
            maxn = size[to];
            son[x] = to;
        }
    }
    return size[x];
}

int tp[M] , dfn[M] , a[M] , cnt;

void dfs2(int x , int topf){
    dfn[x] = ++ cnt;
    a[cnt] = val[x];
    tp[x] = topf;
    if(!son[x]) return;
    dfs2(son[x] , topf);
    PE(i , x){
        int to = edge[i].to;
        if(!dfn[to]){
            dfs2(to , to);
        }
    }
}

namespace Segment_tree{
    #define lson(x) x << 1
    #define rson(x) x << 1 | 1

    struct Node{
        int l , r , len;
        int num , add , maxn , minn , opo;
    }node[M << 2];

    I void pushup(int x){
        node[x].num = (node[lson(x)].num + node[rson(x)].num);
        node[x].maxn = max(node[lson(x)].maxn , node[rson(x)].maxn);
        node[x].minn = min(node[lson(x)].minn , node[rson(x)].minn);
    }

    I void pushdown(int x){
        if(node[x].opo != 1){
            node[lson(x)].opo *= -1; node[lson(x)].num *= -1;
            node[rson(x)].opo *= -1; node[rson(x)].num *= -1;
            int lmax = node[lson(x)].maxn , lmin = node[lson(x)].minn;
            int rmax = node[rson(x)].maxn , rmin = node[rson(x)].minn;
            node[lson(x)].maxn = -lmin; node[lson(x)].minn = -lmax;
            node[rson(x)].maxn = -rmin; node[rson(x)].minn = -rmax;
            node[x].opo = 1;
        } 
        if(node[x].add != 0){
            node[lson(x)].add += node[x].add;
            node[lson(x)].num += node[x].add * node[lson(x)].len;
            node[rson(x)].add += node[x].add;
            node[rson(x)].num += node[x].add * node[rson(x)].len;
            node[x].add = 0;
        }
    }

    void build(int x , int l , int r){
        node[x].l = l; node[x].r = r;
        node[x].len = (r - l + 1);
        node[x].opo = 1;
        if(l == r){
            node[x].num = node[x].maxn = node[x].minn = a[l];
            return ;
        }
        int mid = (node[x].l + node[x].r) >> 1;
        build(lson(x) , l , mid);
        build(rson(x) , mid + 1 , r);
        pushup(x);
    }

    void point_change(int x , int q, int change){
        if(node[x].l == node[x].r){
            node[x].num = change;
            node[x].add = 0;
            node[x].maxn = node[x].minn = change;
            return;
        }
        pushdown(x);
        int mid = (node[x].l + node[x].r) >> 1;
        if(q <= mid){
            point_change(lson(x) , q , change);
        }
        else{
            point_change(rson(x) , q , change);
        }
        pushup(x);
    }

    void range_add(int x , int ql , int qr , int add){
        if(ql <= node[x].l && node[x].r <= qr){
            node[x].add += add;     
            node[x].num += node[x].len * add;
            return ;
        }
        pushdown(x);
        int mid = (node[x].l + node[x].r) >> 1;
        if(ql <= mid){
            range_add(lson(x) , ql , qr , add);
        }
        if(mid + 1 <= qr){
            range_add(rson(x) , ql , qr , add);
        }
        pushup(x);
    }

    void range_opposite(int x , int ql , int qr){
        if(ql <= node[x].l && node[x].r <= qr){
            node[x].opo *= -1;
            node[x].num *= -1;
            int maxn = node[x].maxn , minn = node[x].minn;
            node[x].maxn = -minn; node[x].minn = -maxn;
            return ;
        }
        pushdown(x);
        int mid = (node[x].l + node[x].r) >> 1;
        if(ql <= mid){
            range_opposite(lson(x) , ql , qr);
        }
        if(mid + 1 <= qr){
            range_opposite(rson(x) , ql , qr);
        }
        pushup(x);
    }

    int range_query(int x , int ql , int qr){
        if(ql <= node[x].l && node[x].r <= qr){
            return node[x].num;
        }
        pushdown(x);
        int mid = (node[x].l + node[x].r) >> 1 , ans = 0;
        if(ql <= mid){
            ans += range_query(lson(x) , ql , qr);
        }
        if(mid + 1 <= qr){
            ans += range_query(rson(x) , ql , qr);
        }
        return ans;
    }

    int range_max(int x , int ql , int qr){
        if(ql <= node[x].l && node[x].r <= qr){
            return node[x].maxn;
        }
        pushdown(x);
        int mid = (node[x].l + node[x].r) >> 1 , ans = -0x3f3f3f3f;
        if(ql <= mid){
            ans = max(ans , range_max(lson(x) , ql , qr));
        }
        if(mid + 1 <= qr){
            ans = max(ans , range_max(rson(x) , ql , qr));
        }
        return ans;
    }

    int range_min(int x , int ql , int qr){
        if(ql <= node[x].l && node[x].r <= qr){
            return node[x].minn;
        }
        pushdown(x);
        int mid = (node[x].l + node[x].r) >> 1 , ans = 0x3f3f3f3f;
        if(ql <= mid){
            ans = min(ans , range_min(lson(x) , ql , qr));
        }
        if(mid + 1 <= qr){
            ans = min(ans , range_min(rson(x) , ql , qr));
        }
        return ans;
    }

    #undef lson
    #undef rson
}

void tree_opposite(int x , int y){
    while(tp[x] != tp[y]){
        if(dep[tp[x]] < dep[tp[y]]){
            swap(x , y);
        }
        Segment_tree :: range_opposite(1 , dfn[tp[x]] , dfn[x]);
        x = fa[tp[x]];
    }
    if(x != y){
        if(dep[x] > dep[y]) swap(x , y);
        Segment_tree :: range_opposite(1 , dfn[x] + 1 , dfn[y]);
    }
}

int tree_query(int x , int y){
    int ans = 0;
    while(tp[x] != tp[y]){
        if(dep[tp[x]] < dep[tp[y]]){
            swap(x , y);
        }
        ans += Segment_tree :: range_query(1 , dfn[tp[x]] , dfn[x]);
        x = fa[tp[x]];
    }
    if(x != y){
        if(dep[x] > dep[y]) swap(x , y);
        ans += Segment_tree :: range_query(1 , dfn[x] + 1 , dfn[y]);
    }
    return ans;
}

int tree_max(int x , int y){
    int ans = -0x3f3f3f3f;
    while(tp[x] != tp[y]){
        if(dep[tp[x]] < dep[tp[y]]){
            swap(x , y);
        }
        ans = max(ans , Segment_tree :: range_max(1 , dfn[tp[x]] , dfn[x]));
        x = fa[tp[x]];
    }
    if(x != y){
        if(dep[x] > dep[y]) swap(x , y);
        ans = max(ans , Segment_tree :: range_max(1 , dfn[x] + 1 , dfn[y]));
    }
    return ans;
}

int tree_min(int x , int y){
    int ans = 0x3f3f3f3f;
    while(tp[x] != tp[y]){
        if(dep[tp[x]] < dep[tp[y]]){
            swap(x , y);
        }
        ans = min(ans , Segment_tree :: range_min(1 , dfn[tp[x]] , dfn[x]));
        x = fa[tp[x]];
    }
    if(x != y){
        if(dep[x] > dep[y]) swap(x , y);
        ans = min(ans , Segment_tree :: range_min(1 , dfn[x] + 1 , dfn[y]));    
    }
    return ans;
}

int from1[M] , to1[M];

void change(int x , int y , int val){
    if(dep[x] > dep[y]) swap(x , y);
    Segment_tree :: point_change(1 , dfn[y] , val);
}

int main() {
    #ifdef LOCAL
        freopen("P1505_4.in" , "r" , stdin);
        freopen("P1505_4.out" , "w" , stdout);
    #endif
    int n; scanf("%d" , &n);
    int u , v , d;
    rep(i , 1 , n - 1){
        scanf("%d%d%d" , &u , &v , &d);
        u ++; v ++;
        add_edge(u , v , d);
        from1[i] = u; to1[i] = v;
    }
    dfs1(1 , 0 , 1);
    dfs2(1 , 1);
    Segment_tree :: build(1 , 1 , n);

    int m; scanf("%d" , &m);
    char opt[10];
    int x , y;
    while(m --){
        scanf("%s" , opt);
        scanf("%d%d" , &x , &y);
        if(opt[0] == 'C'){
            change(from1[x] , to1[x] , y);
        }
        else if(opt[0] == 'N'){
            x ++; y ++;
            tree_opposite(x , y);
        }
        else if(opt[0] == 'S'){
            x ++; y ++;
            printf("%d\n" , tree_query(x , y));
        }
        else{
            if(opt[1] == 'A'){
                x ++ , y ++;
                printf("%d\n" , tree_max(x , y));
            }
            else if(opt[1] == 'I'){
                x ++ , y ++;
                printf("%d\n" , tree_min(x , y));
            }
        }
    }

    return 0;
}

THE END