#include<bits/stdc++.h>
using namespace std;
 
#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)
 
#define ll long long
#define ull unsigned ll
 
#define mygc(c) (c)=getchar_unlocked()
#define mypc(c) putchar_unlocked(c)
 
void reader(int *x){int k,m=0;*x=0;for(;;){mygc(k);if(k=='-'){m=1;break;}if('0'<=k&&k<='9'){*x=k-'0';break;}}for(;;){mygc(k);if(k<'0'||k>'9')break;*x=(*x)*10+k-'0';}if(m)(*x)=-(*x);}
void reader(int *x, int *y){reader(x);reader(y);}
void reader(int *x, int *y, int *z){reader(x);reader(y);reader(z);}
void writer(int x, char c){int sz=0,m=0;char buf[10];if(x<0)m=1,x=-x;while(x)buf[sz++]=x%10,x/=10;if(!sz)buf[sz++]=0;if(m)mypc('-');while(sz--)mypc(buf[sz]+'0');mypc(c);}
 
template<class T>
struct ullHash{
  ull *key; T *val; unsigned memory, size, mask;
 
  void clear(){memset(val,0,size*sizeof(T));}
  void clear(int sz){size=1;while(size<sz)size*=2;mask=size-1;clear();}
  void init(int mem, int sz){memory=mem;size=1;while(size<sz)size*=2;mask=size-1;if(memory<size)memory=size;key=(ull*)malloc(memory*sizeof(ull));val=(T*)malloc(memory*sizeof(T));if(size)clear();}
  int function(ull a){return (a*97531)&mask;}
  T get(ull a){int i=function(a);for(;key[i]!=a&&val[i]!=0;)i=(i+1)&mask;if(key[i]!=a) return 0;return val[i];}
  void set(ull a, T v){int i=function(a);for(;key[i]!=a&&val[i]!=0;)i=(i+1)&mask;key[i]=a;val[i]=v;}
  T increase(ull a, T v = 1){int i=function(a);for(;key[i]!=a&&val[i]!=0;)i=(i+1)&mask;key[i]=a;return val[i]+=v;}
};
 
template<class T>
struct segtreeMinVal{
  int size, mem; T *val, *minVal;
 
  void malloc(int N){mem=N;val=(T*)std::malloc(sizeof(T)*N);minVal=(T*)std::malloc(sizeof(T)*N*4);}
  void free(void){mem=0;std::free(val);std::free(minVal);}
  void init_sub(int node, int left, int right){int sz=right-left,n1=node*2+1,n2=node*2+2;if(sz==1)minVal[node]=val[left];else {init_sub(n1,left,left+sz/2);init_sub(n2,left+sz/2,right);minVal[node]=min(minVal[n1], minVal[n2]);}}
  void init(int N, int zerofill = 0){int i;size=N;if(zerofill)rep(i,N)val[i]=0;init_sub(0,0,N);}
  void change_sub(int node, int left, int right, int n){int sz=right-left,n1=node*2+1,n2=node*2+2;if(n<left||n>=right)return;if(sz==1)minVal[node]=val[left];else {change_sub(n1,left,left+sz/2,n);change_sub(n2,left+sz/2,right,n);minVal[node]=min(minVal[n1],minVal[n2]);}}
  void change(int n, T v){if(val[n]==v)return;val[n]=v;change_sub(0,0,size,n);}
  T get_minVal_sub(int node, int left, int right, int a, int b){int sz=right-left,n1=node*2+1,n2=node*2+2;if(a<left)a=left;if(b>right)b=right;if(a>=b)return numeric_limits<T>::max();if(a==left&&b==right)return minVal[node];return min(get_minVal_sub(n1,left,left+sz/2,a,b), get_minVal_sub(n2,left+sz/2,right,a,b));}
  T get_minVal(int a, int b){return get_minVal_sub(0,0,size,a,b);}
};
 
 
#define INF 2000000001
 
int N, M, Q;
int U[210000], V[210000], C[210000];
int TYPE, S, T, X, NEW_CAPACITY;
 
ullHash<int> node2edge;
ullHash<int> treeNode2edge;
 
int edgeind_edgeU[210000], edgeind_edgeV[210000];
vector<int> edge[110000], cap[110000];
 
int cycleSize;
vector<int> cycle[110000];
int node2cycle[110000], node2cycle_ind[110000];
 
 
int route[110000], visited[110000];
void find_cycle(int node, int depth, int bef){
  int i, j, k;
 
  visited[node] = depth;
  route[depth] = node;
 
  rep(i,edge[node].size()){
    k = edge[node][i];
    if(k==bef) continue;
 
    if(visited[k] >= 0){
      if(visited[k] <= depth){
        cycle[cycleSize].clear();
        REP(j,visited[k],depth+1) cycle[cycleSize].push_back(route[j]);
        cycleSize++;
      }
    } else {
      find_cycle(k, depth+1, node);
    }
  }
}
 
 
 
 
int treeN;
int node2treeNode[110000], cycle2treeNode[110000], treeNode2cycle[110000];
int treeNodeType[110000], treeNodeInd[110000]; // TYPE : 0 = ordinary node, 1 = cycle
vector<int> treeEdge[110000];
 
int blockSize;
int treeNode2Block[110000], treeNode2Ind[110000];
int upBlock[110000], upInd[110000];
vector<int> block2node[110000];
vector<int> downBlock[110000], downFrom[110000];
int blockDepth[110000];
 
int subtreeSize[110000];
 
void getTreeSizeDfs(int node, int bef){
  int i, k;
  subtreeSize[node] = 1;
  rep(i,treeEdge[node].size()){
    k = treeEdge[node][i];
    if(k==bef) continue;
    getTreeSizeDfs(k, node);
    subtreeSize[node] += subtreeSize[k];
  }
}
 
void genBlock(int node, int bef, int bef_ind){
  int i, k, mx, mx_ind;
  int block = blockSize++;
 
  if(bef >= 0){
    upBlock[block] = treeNode2Block[bef];
    upInd[block] = bef_ind;
    blockDepth[block] = blockDepth[upBlock[block]] + 1;
  } else{
    blockDepth[block] = 0;
  }
 
  downBlock[block].clear();
  downFrom[block].clear();
  block2node[block].clear();
  block2node[block].push_back(node);
 
  treeNode2Block[node] = block;
  treeNode2Ind[node] = 0;
 
  for(;;){
    mx = mx_ind = -1;
    rep(i,treeEdge[node].size()){
      k = treeEdge[node][i];
      if(k==bef) continue;
      if(mx < subtreeSize[k]){
        mx = subtreeSize[k];
        mx_ind = i;
      }
    }
    if(mx==-1) break;
 
    rep(i,treeEdge[node].size()){
      if(i==mx_ind) continue;
      k = treeEdge[node][i];
      if(k==bef) continue;
      downBlock[block].push_back(blockSize);
      downFrom[block].push_back(block2node[block].size()-1);
      genBlock(k, node, block2node[block].size()-1);
    }
 
    bef = node;
    node = treeEdge[node][mx_ind];
    block2node[block].push_back(node);
 
    treeNode2Block[node] = block;
    treeNode2Ind[node] = block2node[block].size()-1;
  }
}
 
int topNodeOfBlock[110000], upNodeOfBlock[110000];
vector<int> topNodeOfTreeNode[110000], bottomNodeOfTreeNode[110000];
 
int edgeType[210000]; // 0 = in cycle, 1 = heavy edge, 2 = light edge
int edge2cycle[210000], edge2cycle_ind[210000];
int edge2block[210000], edge2block_ind[210000];
 
segtreeMinVal<int> segCycle[110000], segBlock[110000];
 
 
int solveCycle(int a, int b){
  if(a==b || node2cycle[a]==-1) return INF;
  assert( node2cycle[a] != -1 && node2cycle[a] == node2cycle[b] );
  
  int res = 0;
  int c = node2cycle[a];
  a = node2cycle_ind[a];
  b = node2cycle_ind[b];
  if(a > b) swap(a, b);
 
  res += segCycle[c].get_minVal(a,b);
  res += min(segCycle[c].get_minVal(0,a), segCycle[c].get_minVal(b,cycle[c].size()));
 
  return res;
}
 
int solveBlock(int a, int b){
  int res = INF;
 
  assert(treeNode2Block[node2treeNode[a]] == treeNode2Block[node2treeNode[b]]);
  int bl = treeNode2Block[node2treeNode[a]];
  if(treeNode2Ind[node2treeNode[a]] == treeNode2Ind[node2treeNode[b]]) return solveCycle(a, b);
 
  if(treeNode2Ind[node2treeNode[a]] > treeNode2Ind[node2treeNode[b]]) swap(a,b);
 
  int ai = treeNode2Ind[node2treeNode[a]], bi = treeNode2Ind[node2treeNode[b]];
  res = min(res, solveCycle(a, bottomNodeOfTreeNode[bl][ai]));
  res = min(res, solveCycle(b, topNodeOfTreeNode[bl][bi]));
 
  res = min(res, segBlock[bl].get_minVal(ai*2+2, bi*2+1));
  
  return res;
}
 
int solve(int a, int b){
  int res = INF;
  int bl, ai;

  for(;;){
    if(treeNode2Block[node2treeNode[a]] == treeNode2Block[node2treeNode[b]]){
      res = min(res, solveBlock(a, b));
      break;
    }
 
    if(blockDepth[treeNode2Block[node2treeNode[a]]] < blockDepth[treeNode2Block[node2treeNode[b]]]) swap(a, b);
    bl = treeNode2Block[node2treeNode[a]];
    ai = treeNode2Ind[node2treeNode[a]];
 
    res = min(res, solveCycle(a, topNodeOfTreeNode[bl][ai]) );
    res = min(res, segBlock[bl].get_minVal(0, ai*2+1));
 
    a = upNodeOfBlock[treeNode2Block[node2treeNode[a]]];
  }
 
  return res;
}
 
void modify(int e, int v){
  if(edgeType[e]){
    segBlock[edge2block[e]].change(edge2block_ind[e], v);
  } else {
    int tn, bl, ind;
    segCycle[edge2cycle[e]].change(edge2cycle_ind[e], v);
    tn = cycle2treeNode[edge2cycle[e]];
    bl = treeNode2Block[tn];
    ind = treeNode2Ind[tn];
    if(ind < block2node[bl].size()-1){
      segBlock[bl].change(ind*2+1, solveCycle(topNodeOfTreeNode[bl][ind], bottomNodeOfTreeNode[bl][ind]));
    }
  }
}
 
int main(){
  int i, j, k, e, x, y, z;
  int res;
 
  reader(&N,&M);
  rep(i,M){
    reader(U+i,V+i,C+i), U[i]--, V[i]--;
    assert(0 <= U[i] && U[i] < N);
    assert(0 <= V[i] && V[i] < N);
    assert(1 <= C[i] && C[i] <= 1000000000);
  }
 
  node2edge.init(3*M+10, 3*M+10);
  treeNode2edge.init(3*M+10, 3*M+10);
  rep(i,M){
    node2edge.set(U[i]*N+V[i], i+1);
    node2edge.set(V[i]*N+U[i], i+1);
  }
 
  rep(i,N) edge[i].clear(), cap[i].clear();
  rep(i,M){
    edgeind_edgeU[i] = edge[U[i]].size();
    edgeind_edgeV[i] = edge[V[i]].size();
    edge[U[i]].push_back(V[i]); cap[U[i]].push_back(C[i]);
    edge[V[i]].push_back(U[i]); cap[V[i]].push_back(C[i]);
  }
 
  rep(i,N) node2cycle[i] = -1;
  rep(i,N) visited[i] = -1;
  cycleSize = 0;
  find_cycle(0, 0, -1);
 
  rep(i,cycleSize){
    rep(j,cycle[i].size()){
      node2cycle[cycle[i][j]] = i;
      node2cycle_ind[cycle[i][j]] = j;
    }
  }

  treeN = 0;
  rep(i,N){
    if(node2cycle[i]==-1 || node2cycle_ind[i]==0){
      treeNode2cycle[treeN] = node2cycle[i];
      if(node2cycle[i]==-1) node2treeNode[i] = treeN;
      else                  cycle2treeNode[node2cycle[i]] = treeN;
      if(node2cycle[i]==-1) treeNodeType[treeN] = 0, treeNodeInd[treeN] = i;
      else                  treeNodeType[treeN] = 1, treeNodeInd[treeN] = node2cycle[i];
      treeN++;
    }
  }
  rep(i,N) if(node2cycle[i] >= 0) node2treeNode[i] = cycle2treeNode[node2cycle[i]];
 
  rep(i,M){
    if(node2cycle[U[i]] != -1 && node2cycle[U[i]]==node2cycle[V[i]]) continue;
    if(node2cycle[U[i]] == -1) x = node2treeNode[U[i]]; else x = cycle2treeNode[node2cycle[U[i]]];
    if(node2cycle[V[i]] == -1) y = node2treeNode[V[i]]; else y = cycle2treeNode[node2cycle[V[i]]];
    treeEdge[x].push_back(y);
    treeEdge[y].push_back(x);
    treeNode2edge.set(x*N+y, i+1);
    treeNode2edge.set(y*N+x, i+1);
  }

  blockSize = 0;
  getTreeSizeDfs(0, -1);
  genBlock(0, -1, -1);
 
  REP(k,1,blockSize){
    x = block2node[k][0];
    z = block2node[upBlock[k]][upInd[k]];
    e = treeNode2edge.get(x*N+z) - 1; assert("ASSERT 1" && e >= 0);
    edgeType[e] = 2;
    edge2block[e] = k; edge2block_ind[e] = 0;
    if(node2treeNode[U[e]] == x) topNodeOfBlock[k] = U[e], upNodeOfBlock[k] = V[e];
    else                         topNodeOfBlock[k] = V[e], upNodeOfBlock[k] = U[e];
  }
  rep(k,blockSize){
    topNodeOfTreeNode[k].clear();
    bottomNodeOfTreeNode[k].clear();
 
    topNodeOfTreeNode[k].push_back(topNodeOfBlock[k]);
    REP(i,1,block2node[k].size()){
      x = block2node[k][i-1];
      y = block2node[k][i];
      e = treeNode2edge.get(x*N+y) - 1; assert("ASSERT 2" && e >= 0);
      edgeType[e] = 1;
      edge2block[e] = k; edge2block_ind[e] = 2*i;
      if(node2treeNode[U[e]] == x) topNodeOfTreeNode[k].push_back(V[e]), bottomNodeOfTreeNode[k].push_back(U[e]);
      else                         topNodeOfTreeNode[k].push_back(U[e]), bottomNodeOfTreeNode[k].push_back(V[e]);
    }
  }
 
  rep(k,cycleSize){
    segCycle[k].malloc(cycle[k].size());
    rep(i,cycle[k].size()){
      e = node2edge.get(cycle[k][i]*N + cycle[k][(i+1)%cycle[k].size()]) - 1;
      edgeType[e] = 0;
      edge2cycle[e] = k; edge2cycle_ind[e] = i;
      segCycle[k].val[i] = C[e];
    }
    segCycle[k].init(cycle[k].size());
  }
 
  rep(k,blockSize){
    segBlock[k].malloc(2*block2node[k].size()-1);
    rep(i,block2node[k].size()){
      x = block2node[k][i];
 
      if(i){
        z = block2node[k][i-1];
        segBlock[k].val[2*i] = C[ treeNode2edge.get(x*N+z)-1 ];
      } else if(k==0){
        segBlock[k].val[2*i] = INF;
      } else {
        z = block2node[upBlock[k]][upInd[k]];
        segBlock[k].val[2*i] = C[ treeNode2edge.get(x*N+z)-1 ];
      }
 
      if(i+1 < block2node[k].size()){
        if(treeNodeType[x] == 0){
          segBlock[k].val[2*i+1] = INF;
        } else if(k==0 && i==0) {
          segBlock[k].val[2*i+1] = INF;
        } else {
          segBlock[k].val[2*i+1] = solveCycle(topNodeOfTreeNode[k][i], bottomNodeOfTreeNode[k][i]);
        }
      }
    }
    segBlock[k].init(2*block2node[k].size()-1);
  }
  
  reader(&Q);
  while(Q--){
    reader(&TYPE);
    if(TYPE==0){
      reader(&S,&T); S--; T--;
      res = solve(S,T);
      writer(res, '\n');
    } else {
      reader(&X,&NEW_CAPACITY); X--;
      modify(X, NEW_CAPACITY);
    }
  }
 
  return 0;
}