You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

CHANGE i v Change the weight of the ith edge to v
NEGATE a b Negate the weight of every edge on the path from a to b
QUERY a b Find the maximum weight of edges on the path from a to b

Input

The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers ab and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.

Output

For each “QUERY” instruction, output the result on a separate line.

Sample Input

1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output

1
3
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct edge {
	int v, ne;
}ed[maxn * 2];
int head[maxn], cnt, n;
int fa[maxn], son[maxn], num[maxn], deep[maxn];
int p[maxn], fp[maxn], top[maxn];
int pos;
void init() {
	cnt = 0;
	memset(head, -1, sizeof head);
	pos = 0;
	memset(son, -1, sizeof son);
}
void addedge(int u, int v) {
	ed[cnt].v = v;
	ed[cnt].ne = head[u];
	head[u] = cnt++;
}
void dfs1(int u, int pre, int d) {
	deep[u] = d;
	fa[u] = pre;
	num[u] = 1;
	for (int i = head[u]; ~i; i = ed[i].ne) {
		int v = ed[i].v;
		if (v == pre)continue;
		dfs1(v, u, d + 1);
		num[u] += num[v];
		if (son[u] == -1 || num[v] > num[son[u]])
			son[u] = v;
	}
}
void getpos(int u, int sp) {
	top[u] = sp;
	p[u] = pos++;
	fp[p[u]] = u;
	if (son[u] == -1)return;
	getpos(son[u], sp);
	for (int i = head[u]; ~i; i = ed[i].ne) {
		int v = ed[i].v;
		if (v != son[u] && v != fa[u]) {
			getpos(v, v);
		}
	}
}
struct node {
	int l, r;
	int Max, Min, lazy;
}c[maxn * 4];
void build(int rt, int l, int r) {
	c[rt].l = l; c[rt].r = r;
	c[rt].Max = -0x3f3f3f3f, c[rt].Min = 0x3f3f3f3f, c[rt].lazy = 0;
	if (l == r)return;
	int mid = (l + r) >> 1;
	build(rt << 1, l, mid);
	build((rt << 1) | 1, mid + 1, r);
}
void pushup(int rt) {
	c[rt].Max = max(c[rt << 1].Max, c[(rt << 1) | 1].Max);
	c[rt].Min = min(c[(rt << 1)].Min, c[(rt << 1) | 1].Min);
}
void pushdown(int rt) {
	if (c[rt].lazy) {
		c[rt].lazy = 0;
		//
		c[rt << 1].lazy ^= 1;
		swap(c[rt << 1].Max, c[rt << 1].Min);
		c[rt << 1].Max = -c[rt << 1].Max;	c[rt << 1].Min = -c[rt << 1].Min;
		//
		c[(rt << 1) | 1].lazy ^= 1;
		swap(c[(rt << 1) | 1].Max, c[(rt << 1) | 1].Min);
		c[(rt << 1) | 1].Max = -c[(rt << 1) | 1].Max;	c[(rt << 1) | 1].Min = -c[(rt << 1) | 1].Min;
	}
}
void update(int rt, int k, int val) {
	if (c[rt].l == k&&c[rt].r == k) {
		c[rt].Max = val;
		c[rt].Min = val;
		return;
	}
	pushdown(rt);
	int mid = (c[rt].l + c[rt].r) >> 1;
	if (k <= mid)update(rt << 1, k, val);
	else update(((rt << 1) | 1), k, val);
	pushup(rt);
}
void updates(int rt, int l, int r) {
	if (c[rt].l == l&&c[rt].r == r) {
		swap(c[rt].Max, c[rt].Min);
		c[rt].Max = -c[rt].Max;
		c[rt].Min = -c[rt].Min;
		c[rt].lazy ^= 1;
		return;
	}
	pushdown(rt);
	int mid = (c[rt].l + c[rt].r) >> 1;
	if (r <= mid)updates(rt << 1, l, r);
	else if (l > mid)updates((rt << 1) | 1, l, r);
	else {
		updates(rt << 1, l, mid);
		updates((rt << 1) | 1, mid + 1, r);
	}
	pushup(rt);
}
void see(int rt, int l, int r) {
	//if (l == r)
	//	cout << "L:" << fp[l] << " R:" << fp[r] << " Max:" << c[rt].Max << " Min:" << c[rt].Min << endl;
	if (l == r)return;
	pushdown(rt);
	int mid = (l + r) >> 1;
	see(rt << 1, l, mid);
	see((rt << 1) | 1, mid + 1, r);
	pushup(rt);
}
int query(int rt, int l, int r) {
	if (c[rt].l == l&&c[rt].r == r)
		return c[rt].Max;
	int mid = (c[rt].l + c[rt].r) >> 1, ans;
	pushdown(rt);
	if (r <= mid)ans = query(rt << 1, l, r);
	else if (l > mid)ans = query((rt << 1) | 1, l, r);
	else return ans = max(query(rt << 1, l, mid), query((rt << 1) | 1, mid + 1, r));
	return ans;
}
int find(int u, int v) {
	int f1 = top[u], f2 = top[v];
	int tmp = -0x3f3f3f3f;
	while (f1 != f2) {
		if (deep[f1] < deep[f2]) {
			swap(f1, f2);
			swap(u, v);
		}
		tmp = max(tmp, query(1, p[f1], p[u]));
		u = fa[f1]; f1 = top[u];
	}
	if (u == v)return tmp;
	if (deep[u] > deep[v])swap(u, v);
	return max(tmp, query(1, p[son[u]], p[v]));
}
void Change(int u, int v) {
	int f1 = top[u], f2 = top[v];
	while (f1 != f2) {
		if (deep[f1] < deep[f2]) {
			swap(f1, f2);
			swap(u, v);
		}
		//cout << "Change: " << p[f1] << " "<<p[u] << endl;
		updates(1, p[f1], p[u]);
		u = fa[f1]; f1 = top[u];
	}
	if (u == v)return;
	if (deep[u] > deep[v])swap(u, v);
	//cout << "Change: " << p[son[u]] << " " << p[v] << endl;
	updates(1, p[son[u]], p[v]);
}
int e[maxn][3];
int main() {
	int te, n;
	scanf("%d", &te);
	while (te--) {
		scanf("%d", &n);
		init();
		for (int i = 1; i <= n - 1; i++) {
			scanf("%d%d%d", &e[i][0], &e[i][1], &e[i][2]);
			addedge(e[i][0], e[i][1]);
			addedge(e[i][1], e[i][0]);
		}
		dfs1(1, 0, 0);
		getpos(1, 1);
		build(1, 1, n - 1);
		for (int i = 1; i <= n - 1; i++) {
			if (deep[e[i][0]] < deep[e[i][1]]) {
				swap(e[i][0], e[i][1]);
			}
			update(1, p[e[i][0]], e[i][2]);
		}
		char que[10];
		while (scanf("%s", que) != EOF) {
			if (que[0] == 'D')break;
			int a, b;
			scanf("%d%d", &a, &b);
			if (que[0] == 'Q') {
				printf("%d\n", find(a, b));
			}
			else if (que[0] == 'N') {
				Change(a, b);
			}
			else {
				update(1, p[e[a][0]], b);
			}
		}
	}
	return 0;
}