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 |
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
new Task().solve() ;
}
}
class Task {
InputReader in = new InputReader(System.in);
PrintWriter out = new PrintWriter(System.out);
int[] size , top , son ;
int[] dep , tid , fa , rank ;
int dfn , edge ;
int[] head , to , next ;
void addEdge(int u , int v){
to[edge] = v ; next[edge] = head[u] ; head[u] = edge++ ;
to[edge] = u ; next[edge] = head[v] ; head[v] = edge++ ;
}
void findHeavyEdge(int u , int father , int depth){
dep[u] = depth ;
fa[u] = father ;
size[u] = 1 ;
for(int i = head[u] ; i != -1 ; i = next[i]){
int v = to[i] ;
if(v != father){
findHeavyEdge(v , u , depth+1) ;
size[u] += size[v] ;
if(son[u] == -1 || size[v] > size[son[u]])
son[u] = v ;
}
}
}
void connectHeavyEdge(int u , int tp){
top[u] = tp ;
tid[u] = ++dfn ;
rank[tid[u]] = u ;
if(son[u] == -1) return ;
connectHeavyEdge(son[u] , tp) ;
for(int i = head[u] ; i != -1 ; i = next[i]){
int v = to[i] ;
if(v != son[u] && v != fa[u])
connectHeavyEdge(v , v) ;
}
}
int[] max , min , lazy , val ;
void up(int t){
max[t] = Math.max(max[t<<1] , max[t<<1|1]) ;
min[t] = Math.min(min[t<<1] , min[t<<1|1]) ;
}
void negate(int t){
int tm = -max[t] ;
max[t] = -min[t] ;
min[t] = tm ;
}
void down(int t){
if(lazy[t] != 0){
lazy[t<<1] ^= 1 ;
negate(t<<1) ;
lazy[t<<1|1] ^= 1 ;
negate(t<<1|1) ;
lazy[t] = 0 ;
}
}
void build(int l , int r , int t){
lazy[t] = 0 ;
if(l == r){
max[t] = min[t] = val[l] ;
return ;
}
int m = (l + r) >> 1 ;
build(l , m , t<<1) ;
build(m+1 , r , t<<1|1) ;
up(t) ;
}
int query(int L , int R , int l , int r , int t){
if(L <= l && r <= R) return max[t] ;
down(t) ;
int m = (l + r) >> 1 ;
int res = Integer.MIN_VALUE ;
if(L <= m) res = Math.max(res , query(L, R, l, m, t<<1)) ;
if(R > m) res = Math.max(res , query(L, R, m+1, r, t<<1|1)) ;
up(t) ;
return res ;
}
void doChange(int i , int v , int l , int r , int t){
if(l == r){
max[t] = min[t] = v ;
return ;
}
down(t) ;
int m = (l + r) >> 1 ;
if(i <= m) doChange(i, v, l, m, t<<1) ;
else doChange(i, v, m+1, r, t<<1|1) ;
up(t) ;
}
void updateByNegate(int L , int R , int l , int r , int t){
if(L <= l && r <= R){
negate(t) ;
lazy[t] ^= 1 ;
return ;
}
down(t) ;
int m = (l + r) >> 1 ;
if(L <= m) updateByNegate(L, R, l, m, t<<1) ;
if(R > m) updateByNegate(L, R, m+1, r, t<<1|1) ;
up(t) ;
}
void doNegate(int x , int y , int n){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]){
x ^= y ; y ^= x ; x ^= y ;
}
updateByNegate(tid[top[x]], tid[x] , 1, n, 1) ;
x = fa[top[x]] ;
}
if(x == y) return ;
if(dep[x] > dep[y]){
x ^= y ; y ^= x ; x ^= y ;
}
updateByNegate(tid[son[x]], tid[y], 1, n, 1) ;
}
int change(int x , int y , int n){
if(x == y) return 0 ;
int t = Integer.MIN_VALUE ;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]){
x ^= y ; y ^= x ; x ^= y ;
}
t = Math.max(t, query(tid[top[x]], tid[x] , 1, n, 1)) ;
x = fa[top[x]] ;
}
if(x == y) return t ;
if(dep[x] > dep[y]){
x ^= y ; y ^= x ; x ^= y ;
}
t = Math.max(t , query(tid[son[x]], tid[y], 1, n, 1)) ;
return t ;
}
class Line{
int u , v , w ;
Line(int u , int v , int w){
this.u = u ;
this.v = v ;
this.w = w ;
}
}
Line[] lines ;
void init(int n){
size = new int[n+1] ;
top = new int[n+1] ;
son = new int[n+1] ;
dep = new int[n+1] ;
tid = new int[n+1] ;
fa = new int[n+1] ;
rank = new int[n+1] ;
head = new int[n+1] ;
to = new int[n<<1|1] ;
next = new int[n<<1|1] ;
Arrays.fill(head , -1) ;
Arrays.fill(son , -1) ;
dfn = edge = 0 ;
val = new int[n+1] ;
max = new int[n<<2] ;
min = new int[n<<2] ;
lazy = new int[n<<2] ;
lines = new Line[n+1] ;
}
void solve(){
int t = in.nextInt() ;
while(t-- > 0){
int n = in.nextInt() ;
init(n) ;
for(int i = 1 ; i < n ; i++){
lines[i] = new Line(in.nextInt() , in.nextInt() , in.nextInt()) ;
addEdge(lines[i].u , lines[i].v) ;
}
findHeavyEdge(1 , -1 , 0) ;
connectHeavyEdge(1 , 1) ;
for(int i = 1 ; i < n ; i++){
if(tid[lines[i].u] < tid[lines[i].v]){
lines[i].u ^= lines[i].v ;
lines[i].v ^= lines[i].u ;
lines[i].u ^= lines[i].v ;
}
val[tid[lines[i].u]] = lines[i].w ;
}
build(1, n, 1) ;
while(true){
String type = in.next() ;
if("DONE".equals(type)) break ;
if("QUERY".equals(type))
out.println(change(in.nextInt() , in.nextInt() , n)) ;
else if("CHANGE".equals(type))
doChange(tid[lines[in.nextInt()].u], in.nextInt() , 1, n, 1) ;
else doNegate(in.nextInt(), in.nextInt(), n) ;
}
out.flush() ;
}
}
}
class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = new StringTokenizer("");
}
private void eat(String s) {
tokenizer = new StringTokenizer(s);
}
public String nextLine() {
try {
return reader.readLine();
} catch (Exception e) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String s = nextLine();
if (s == null)
return false;
eat(s);
}
return true;
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}