// implment 1h10min // debug1 14min // debug2 7min // implement2 13min #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; static const double EPS = 1e-9; static const double PI = acos(-1.0); #define REP(i, n) for (int i = 0; i < (int)(n); i++) #define FOR(i, s, n) for (int i = (s); i < (int)(n); i++) #define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++) #define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++) #define MEMSET(v, h) memset((v), h, sizeof(v)) struct Node { int ans; int left; int right; int all; Node() {;} Node(int v) : ans(v), left(v), right(v), all(v) {;} }; inline Node Merge(Node left, Node right) { Node ret; ret.left = max(left.left, left.all + right.left); ret.right = max(right.right, right.all + left.right); ret.all = left.all + right.all; ret.ans = max(left.right + right.left, max(left.ans, right.ans)); return ret; } struct SegmentTree { //static const int MAX_DEPTH = 17; //static const int SIZE = 1 << (MAX_DEPTH + 1); // 2^18 = 262144 int MAX_DEPTH; int SIZE; vector updated; vector data; SegmentTree() {;} SegmentTree(int size) { SIZE = 1; MAX_DEPTH = 0; while (SIZE < size) { MAX_DEPTH++; SIZE <<= 1; } SIZE <<= 1; updated = vector(SIZE, false); data = vector(SIZE, Node(-100000)); } void set(int left, int right, Node v) { assert(left <= right); return in_set(v, 0, 1, left, right); } Node get(int left, int right) { assert(left <= right); return in_get(0, 1, left, right); } private: void Divide(int node) { if (!updated[node] || node >= (1 << MAX_DEPTH)) { return; } updated[node] = false; updated[node * 2] = true; updated[node * 2 + 1] = true; if (data[node].all < 0) { data[node * 2] = data[node]; data[node * 2].all = data[node].all / 2; } else { data[node * 2] = Node(data[node].all / 2); } data[node * 2 + 1] = data[node * 2]; } void in_set(Node v, int depth, int node, int left, int right) { int width = 1 << (MAX_DEPTH - depth); int index = node - (1 << depth); int node_left = index * width; int node_mid = node_left + (width >> 1); Divide(node); if (right - left + 1 == width && left == node_left) { updated[node] = true; if (v.all < 0) { data[node] = Node(v.all); data[node].all = v.all * width; } else { data[node] = Node(v.all * width); } } else { if (right < node_mid) { in_set(v, depth + 1, node * 2, left, right); } else if (left >= node_mid) { in_set(v, depth + 1, node * 2 + 1, left, right); } else { in_set(v, depth + 1, node * 2, left, node_mid - 1); in_set(v, depth + 1, node * 2 + 1, node_mid, right); } data[node] = Merge(data[node * 2], data[node * 2 + 1]); } } Node in_get(int depth, int node, int left, int right) { int width = 1 << (MAX_DEPTH - depth); int index = node - (1 << depth); int node_left = index * width; int node_mid = node_left + (width >> 1); Divide(node); if (right - left + 1 == width && left == node_left) { return data[node]; } else if (right < node_mid) { return in_get(depth + 1, node * 2, left, right); } else if (left >= node_mid) { return in_get(depth + 1, node * 2 + 1, left, right); } return Merge(in_get(depth + 1, node * 2, left, node_mid - 1), in_get(depth + 1, node * 2 + 1, node_mid, right)); } }; typedef int Weight; struct Edge { int src; int dest; Weight weight; Edge(int src, int dest, Weight weight) : src(src), dest(dest), weight(weight) {;} bool operator<(const Edge &rhs) const { if (weight != rhs.weight) { return weight > rhs.weight; } if (src != rhs.src) { return src < rhs.src; } return dest < rhs.dest; } }; typedef vector Edges; typedef vector Graph; typedef vector Array; typedef vector Matrix; void PrintMatrix(const Matrix &matrix) { for (int y = 0; y < (int)matrix.size(); y++) { for (int x = 0; x < (int)matrix[y].size(); x++) { printf("%d ", matrix[y][x]); } puts(""); } } struct HeavyLightDecomposition { struct Chain { int depth; pair parent; // chain number, index vector > child; // child chain number, parent index vector mapfrom; SegmentTree stree; }; Graph baseG; vector chains; vector > mapto; vector > mapfrom; HeavyLightDecomposition() {;} HeavyLightDecomposition(const Graph &g) { baseG = g; Init(); } void Init() { const int n = baseG.size(); mapto = vector >(n, make_pair(-1, -1)); mapfrom.clear(); vector size(n, 0); int start = -1; for (int i = 0; i < n; i++) { if (baseG[i].size() <= 1) { start = i; break; } } assert(start != -1); SizeCheckBfs(start, size); Decomposition(start, start, 0, 0, 0, size); } int Depth(int t) { return chains[mapto[t].first].depth; } bool SameChain(int f, int t) { return mapto[f].first == mapto[t].first; } private: int Decomposition(int from, int parent, int depth, int pnumber, int pindex, vector &size) { const int c = chains.size(); chains.push_back(Chain()); chains[c].depth = depth; chains[c].parent = make_pair(pnumber, pindex); vector seq; Bfs(from, parent, seq, size); for (int i = 0; i < (int)seq.size(); i++) { mapto[seq[i]] = make_pair(c, i); chains[c].mapfrom.push_back(seq[i]); } chains[c].stree = SegmentTree(seq.size()); for (int i = 0; i < (int)seq.size(); i++) { for (Edges::const_iterator it = baseG[seq[i]].begin(); it != baseG[seq[i]].end(); it++) { if (mapto[it->dest].first != -1) { continue; } int nc = Decomposition(it->dest, seq[i], depth + 1, c, i, size); chains[c].child.push_back(make_pair(nc, i)); } } return c; } void SizeCheckBfs(int start, vector &size) { const int n = baseG.size(); queue > que; que.push(make_pair(start, start)); int cnt = 0; vector order(n, -1); while (!que.empty()) { int from = que.front().first; int parent = que.front().second; que.pop(); order[cnt++] = from; for (Edges::const_iterator it = baseG[from].begin(); it != baseG[from].end(); it++) { if (it->dest == parent) { continue; } que.push(make_pair(it->dest, from)); } } assert(cnt == n); reverse(order.begin(), order.end()); REP(i, n) { int from = order[i]; size[from] = 1; for (Edges::const_iterator it = baseG[from].begin(); it != baseG[from].end(); it++) { size[from] += size[it->dest]; } } } void Bfs(int from, int parent, vector &seq, const vector &size) { while (true) { seq.push_back(from); int best = -1; int next = -1; for (Edges::const_iterator it = baseG[from].begin(); it != baseG[from].end(); it++) { if (it->dest == parent) { continue; } if (best < size[it->dest]) { best = size[it->dest]; next = it->dest; } } if (next == -1) { break; } parent = from; from = next; } } }; int n, q; int w[200010]; Graph baseG; HeavyLightDecomposition chains; void Change(int t, int w) { int c = chains.mapto[t].first; int index = chains.mapto[t].second; chains.chains[c].stree.set(index, index, w); } int Query(int type, int f, int t, int w) { Node fNode(-1000000); Node tNode(-1000000); while (!chains.SameChain(f, t)) { if (chains.Depth(f) < chains.Depth(t)) { swap(f, t); swap(fNode, tNode); } int c = chains.mapto[f].first; int index = chains.mapto[f].second; if (type == 1) { chains.chains[c].stree.set(0, index, Node(w)); } else { Node temp = chains.chains[c].stree.get(0, index); fNode = Merge(temp, fNode); } int nc = chains.chains[c].parent.first; int nindex = chains.chains[c].parent.second; f = chains.chains[nc].mapfrom[nindex]; } int c = chains.mapto[f].first; int index1 = chains.mapto[f].second; int index2 = chains.mapto[t].second; if (index1 > index2) { swap(index1, index2); swap(f, t); swap(fNode, tNode); } if (type == 1) { chains.chains[c].stree.set(index1, index2, w); } else { Node center = chains.chains[c].stree.get(index1, index2); center = Merge(center, tNode); swap(fNode.left, fNode.right); center = Merge(fNode, center); return center.ans; } return 0; } int main() { while (scanf("%d %d", &n, &q) > 0) { baseG = Graph(n); REP(i, n) { int v = scanf("%d", &w[i]); assert(v == 1); } REP(i, n - 1) { int s, e; int v = scanf("%d %d", &s, &e); assert(v == 2); s--; e--; baseG[s].push_back(Edge(s, e, 0)); baseG[e].push_back(Edge(e, s, 0)); } chains = HeavyLightDecomposition(baseG); REP(i, n) { Change(i, w[i]); } REP(i, q) { int t, a, b, c; int v = scanf("%d %d %d %d", &t, &a, &b, &c); assert(v == 4); a--; b--; int ans = Query(t, a, b, c); if (t == 2) { printf("%d\n", ans); } } } }