#include using namespace std; #define REP(i,a,b) for(i=a;i'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 i,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 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 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=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(aright)b=right;if(a>=b)return numeric_limits::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[200200], V[200200], C[200200]; int TYPE, S, T, X, NEW_CAPACITY; ullHash node2edge; ullHash treeNode2edge; int edgeind_edgeU[200200], edgeind_edgeV[200200]; vector edge[100100], cap[100100]; int cycleSize; vector cycle[100100]; int node2cycle[100100], node2cycle_ind[100100]; int route[100100], visited[100100]; 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[100100], cycle2treeNode[100100], treeNode2cycle[100100]; int treeNodeType[100100], treeNodeInd[100100]; // TYPE : 0 = ordinary node, 1 = cycle vector treeEdge[100100]; int blockSize; int treeNode2Block[100100], treeNode2Ind[100100]; int upBlock[100100], upInd[100100]; vector block2node[100100]; vector downBlock[100100], downFrom[100100]; int blockDepth[100100]; int subtreeSize[100100]; 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, j, 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[100100], upNodeOfBlock[100100]; vector topNodeOfTreeNode[100100], bottomNodeOfTreeNode[100100]; int edgeType[200200]; // 0 = in cycle, 1 = heavy edge, 2 = light edge int edge2cycle[200200], edge2cycle_ind[200200]; int edge2block[200200], edge2block_ind[200200]; segtreeMinVal segCycle[100100], segBlock[100100]; int solveCycle(int a, int b){ if(a==b) 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, a, b, e, x, y, z; int mn, res; reader(&N,&M); rep(i,M) reader(U+i,V+i,C+i), U[i]--, V[i]--; 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; }