<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

529. It's Time to Repair the Roads
Time limit per test: 2.75 second(s)
Memory limit: 262144 kilobytes
input: standard
output: standard

Everybody knows about the problems with roads in Berland. The government has been trying to undertake major repairs for many years, but the roads have never been repaired due to the lack of money in the budget.

There are n cities and m roads in Berland. The cities are numbered from 1 to n. The roads are numbered from 1 to m. Each road connects a pair of different cities, all the roads are two-way. There is at most one road between any pair of cities. The cost of repairing is known for each road.

Clearly, repairing all roads in Berland is an unaffordable luxury, so the government decided to repair only such set of the roads, that it's possible to get from any city to any other city by the roads from this repaired set, and the total cost of these road works is minimal.

In the circumstances of the global economic crisis and global warming, road repair costs change every day. Berland's scientists managed to predict these changes, concluding that the cost of road works will change for only one road each day. They created a full list of expected changes for the coming t days — for each day they came up a road and its new repair cost.

The government of Berland would like to know when it would be better to repair the roads, so they need to figure out the cost of road works for every of the coming t days before making a final decision. Your task is to help them and figure out the total repair cost of Berland's road system at the end of each these t days. As repair costs change over time, the set of selected roads can change on a daily basis as well.

Input
The first line contains a pair of integers n,m (2 ≤ n ≤ 40000, n - 1 ≤ m ≤ 40000), where n — the amount of cities, m — the amount of roads. Each of the following m lines contains a road description: three integer numbers xi, yi and pi (1 ≤ xi, yi ≤ n, xi ≠ yi, 1 ≤ pi ≤ 40000), where xi and yi are indices of the cities connected by the given road, and pi — initial cost of repairing it.

Then there follows a line with the only number t (1 ≤ t ≤ 40000), t — amount of days. The following t lines contain the scientists' predictions for the coming t days. Each of t lines contains a pair of integer numbers ei, ci (1 ≤ ei ≤ m, 1 ≤ ci ≤ 40000), where ci — is the new repair cost for the road ei.

It's possible to get from any city to any other city by the roads. The cost of repair for a single road can be changed more than once over time.

Output
Output t lines, each of them should contain the road system's total repair cost at the end of each day.

Example(s)
sample input
sample output
4 6
1 2 10
2 3 20
2 4 30
1 3 40
3 4 50
4 1 60
3
4 22
5 17
4 14
60
47
41

sample input
sample output
3 3
3 2 4
3 1 4
2 1 3
3
2 5
2 2
2 5
7
5
7

<|response|>
1. Abridged Problem Statement  
   You have an undirected connected graph with n vertices and m edges, each edge having an initial weight. There are t days; on day i, the weight of one specified edge is changed. After each change, report the total weight of the minimum spanning tree (MST) of the current graph.

2. Key Observations  
   a. Recomputing the MST from scratch in O(m log m) per update is too slow for m,t up to 4·10^4.  
   b. We can process the t updates offline in blocks of size B (e.g. B≈200).  
   c. In each block:  
      - Mark the B edges that will change.  
      - Build a “baseline” MST ignoring those B edges (one DSU pass over all m edges).  
      - Contract each connected component of this baseline MST into a super-node.  
      - Among the non-updated edges, pick those that still connect different super-nodes—these are at most n–1 edges.  
      - Append the B updated edges (with their current weights) to form a small list of size ≲n+B. Sort it once.  
      - For each query in the block: adjust the one changed edge’s weight in that small list (by a local swap in the sorted array) and rerun Kruskal on ≲n+B edges to get the new MST cost in O((n+B) α(n)).  
      - Finally merge the updated edges back into the global sorted‐by‐weight edge list in O(m+B) to prepare for the next block.

3. Full Solution Approach  
   Let edges be stored in an array ed[0…m−1], always kept sorted by weight. Let queries be q[0…t−1], each (edge_id, new_weight). Maintain an array answer[0…t−1].  
   - Preprocess: sort ed by weight; record pos[edge_id] = its index in ed.  
   - Process queries in blocks of size B: for block covering queries [L…R):  
     1. Build a boolean usedOld[0…m−1], marking positions in ed of the edges that will change in this block.  
     2. Baseline MST: DSU tmp over n vertices; another DSU compDSU to record which vertices get unified.  
        For i=0…m−1 in increasing weight: if not usedOld[i] and tmp.unite(u,v), add ed[i].w to baseSum and compDSU.unite(u,v).  
     3. Compress components: assign each original vertex v a super‐node id superId[v] = index of compDSU.find(v) in [0…compCnt−1].  
     4. Build “important” edge list imp[]:  
        a. DSU smallDSU over compCnt super‐nodes.  
        b. For i=0…m−1, if not usedOld[i], let cu=superId[u], cv=superId[v]; if smallDSU.unite(cu,cv), add ed[i] to imp and mark used2[ed[i].id]=true.  
        c. For each i where usedOld[i] is true, add ed[i] to imp.  
        Sort imp by weight.  
     5. For each query j in [L…R):  
        – Let (eid,newW)=q[j]. Find the single k in imp with imp[k].id==eid, set imp[k].w=newW, then “bubble” it by at most one swap left or right to restore sorted order locally.  
        – Run Kruskal on imp with DSU krusDSU over compCnt super‐nodes: total=baseSum; for e in imp in weight order, if krusDSU.unite(superId[e.u],superId[e.v]) add e.w to total. Record answer[j]=total.  
     6. Merge updated edges back into ed to restore global sorted order (skipping entries where usedOld[i]=true, and skipping imp‐edges marked used2): two‐pointer merge of old ed and imp. Rebuild pos[].  
   - Output answer[0…t−1].

4. C++ Implementation

```cpp
#include <bits/stdc++.h>
using namespace std;

// DSU with path compression and union by size
struct DSU {
    vector<int> p, sz;
    DSU(int n=0) { init(n); }
    void init(int n) {
        p.resize(n); sz.assign(n,1);
        iota(p.begin(), p.end(), 0);
    }
    int find(int x) { return p[x]==x ? x : p[x]=find(p[x]); }
    bool unite(int a, int b) {
        a = find(a); b = find(b);
        if(a==b) return false;
        if(sz[a]<sz[b]) swap(a,b);
        p[b]=a; sz[a]+=sz[b];
        return true;
    }
};

struct Edge {
    int u, v, w, id;
};

const int MAXM = 40005;
const int BLOCK = 200;

int n, m, t;
Edge ed[MAXM], newEd[MAXM], imp[MAXM + BLOCK];
int posInEd[MAXM];
bool usedOld[MAXM], used2[MAXM];
long long answer[40005];
pair<int,int> queries[40005];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    // 1) Read graph
    cin >> n >> m;
    for(int i=0; i<m; i++){
        cin >> ed[i].u >> ed[i].v >> ed[i].w;
        ed[i].u--; ed[i].v--;
        ed[i].id = i;
    }
    // Sort edges by weight
    sort(ed, ed+m, [](auto &a, auto &b){ return a.w < b.w; });
    for(int i=0; i<m; i++){
        posInEd[ ed[i].id ] = i;
    }

    // 2) Read queries
    cin >> t;
    for(int i=0; i<t; i++){
        cin >> queries[i].first >> queries[i].second;
        queries[i].first--; // zero-based edge id
    }

    // 3) Process in blocks
    for(int L=0; L<t; L+=BLOCK){
        int R = min(t, L+BLOCK);

        // Mark edges that will change in this block
        fill(usedOld, usedOld+m, false);
        for(int i=L; i<R; i++){
            int eid = queries[i].first;
            usedOld[ posInEd[eid] ] = true;
        }

        // Baseline MST ignoring these edges
        DSU tmp(n), compDSU(n);
        long long baseSum = 0;
        for(int i=0; i<m; i++){
            if(usedOld[i]) continue;
            auto &e = ed[i];
            if(tmp.unite(e.u, e.v)){
                baseSum += e.w;
                compDSU.unite(e.u, e.v);
            }
        }

        // Prepare answers = baseSum for all queries in block
        for(int i=L; i<R; i++) answer[i] = baseSum;

        // Compress components -> super-nodes
        vector<int> compId(n, -1);
        int compCnt = 0;
        for(int v=0; v<n; v++){
            int r = compDSU.find(v);
            if(compId[r] < 0) compId[r] = compCnt++;
        }
        for(int v=0; v<n; v++){
            compId[v] = compId[ compDSU.find(v) ];
        }

        // Build important edge list
        DSU smallDSU(compCnt);
        int psz = 0;
        // (a) non-updated edges that connect different super-nodes
        for(int i=0; i<m; i++){
            if(usedOld[i]) continue;
            auto &e = ed[i];
            int cu = compId[e.u], cv = compId[e.v];
            if(smallDSU.unite(cu, cv)){
                imp[psz++] = e;
                used2[e.id] = true;
            }
        }
        // (b) add the B updated edges (with their current old weights)
        for(int i=0; i<m; i++){
            if(usedOld[i]){
                imp[psz++] = ed[i];
            }
        }
        // sort once by weight
        sort(imp, imp+psz, [](auto &a, auto &b){ return a.w < b.w; });

        // Answer each query in the block
        for(int qi=L; qi<R; qi++){
            auto [eid, newW] = queries[qi];
            // 1) update that edge's weight in imp[]
            for(int k=0; k<psz; k++){
                if(imp[k].id == eid){
                    imp[k].w = newW;
                    // bubble it locally
                    if(k+1<psz && imp[k+1].w < imp[k].w) swap(imp[k], imp[k+1]);
                    else if(k>0 && imp[k].w < imp[k-1].w) swap(imp[k], imp[k-1]);
                    break;
                }
            }
            // 2) small Kruskal over imp[] on super-nodes
            DSU krusDSU(compCnt);
            long long total = baseSum;
            for(int k=0; k<psz; k++){
                int cu = compId[ imp[k].u ], cv = compId[ imp[k].v ];
                if(krusDSU.unite(cu, cv)){
                    total += imp[k].w;
                }
            }
            answer[qi] = total;
        }

        // Merge updated edges back into ed[] to keep it sorted
        int i=0, j=0, p=0;
        while(i<m && j<psz){
            // skip old entries that changed
            if(usedOld[i]){ i++; continue; }
            // skip important non-updated edges already in ed[]
            if(used2[ imp[j].id ]){ j++; continue; }
            // pick smaller
            if(ed[i].w < imp[j].w){
                newEd[p++] = ed[i++];
            } else {
                newEd[p++] = imp[j++];
            }
        }
        // remaining old edges
        while(i<m){
            if(!usedOld[i]) newEd[p++] = ed[i];
            i++;
        }
        // remaining imp edges
        while(j<psz){
            if(!used2[ imp[j].id ]) newEd[p++] = imp[j];
            j++;
        }
        // copy back and rebuild posInEd
        for(int k=0; k<m; k++){
            ed[k] = newEd[k];
            posInEd[ ed[k].id ] = k;
        }
        // reset used2 flags
        for(int k=0; k<psz; k++){
            used2[ imp[k].id ] = false;
        }
    }

    // 4) Output answers
    for(int i=0; i<t; i++){
        cout << answer[i] << "\n";
    }
    return 0;
}
```

5. Python Implementation

```python
import sys
sys.setrecursionlimit(10**7)
input = sys.stdin.readline

class DSU:
    def __init__(self,n):
        self.p = list(range(n))
        self.sz = [1]*n
    def find(self,x):
        while self.p[x]!=x:
            self.p[x] = self.p[self.p[x]]
            x = self.p[x]
        return x
    def unite(self,a,b):
        a,b = self.find(a), self.find(b)
        if a==b: return False
        if self.sz[a]<self.sz[b]:
            a,b = b,a
        self.p[b]=a
        self.sz[a]+=self.sz[b]
        return True

n,m = map(int,input().split())
edges = []
for i in range(m):
    u,v,w = map(int,input().split())
    edges.append([u-1,v-1,w,i])
# keep edges sorted by weight
edges.sort(key=lambda e:e[2])
# map edge id -> position in edges[]
pos = [0]*m
for idx,e in enumerate(edges):
    pos[e[3]] = idx

t = int(input())
queries = [tuple(map(int,input().split())) for _ in range(t)]
# zero-based edge index
queries = [(e-1,c) for (e,c) in queries]

B = 200
ans = [0]*t

for L in range(0, t, B):
    R = min(t, L+B)
    # mark which positions in edges[] will change
    will = [False]*m
    for i in range(L,R):
        eid,_ = queries[i]
        will[pos[eid]] = True

    # 1) baseline MST ignoring these edges
    d0 = DSU(n)
    base = 0
    for i,(u,v,w,eid) in enumerate(edges):
        if will[i]: continue
        if d0.unite(u,v):
            base += w

    # assign each vertex a super-node id
    comp_map = {}
    compCnt = 0
    superId = [0]*n
    for v in range(n):
        r = d0.find(v)
        if r not in comp_map:
            comp_map[r] = compCnt
            compCnt += 1
        superId[v] = comp_map[r]

    # 2) collect important edges
    d1 = DSU(compCnt)
    imp = []
    used2 = [False]*m
    # (a) non-updated edges that connect components
    for i,(u,v,w,eid) in enumerate(edges):
        if will[i]: continue
        cu,cv = superId[u], superId[v]
        if d1.unite(cu,cv):
            imp.append([u,v,w,eid])
            used2[eid] = True
    # (b) add the edges to be updated (with their old weight)
    for i,(u,v,w,eid) in enumerate(edges):
        if will[i]:
            imp.append([u,v,w,eid])
    # sort once
    imp.sort(key=lambda e:e[2])

    # 3) answer each query in block
    for qi in range(L,R):
        eid,newW = queries[qi]
        # update in imp
        for k in range(len(imp)):
            if imp[k][3] == eid:
                imp[k][2] = newW
                # bubble adjust
                if k+1<len(imp) and imp[k+1][2] < imp[k][2]:
                    imp[k],imp[k+1] = imp[k+1],imp[k]
                elif k>0 and imp[k][2] < imp[k-1][2]:
                    imp[k],imp[k-1] = imp[k-1],imp[k]
                break
        # small Kruskal on imp
        d2 = DSU(compCnt)
        total = base
        for u,v,w,eid2 in imp:
            cu,cv = superId[u], superId[v]
            if d2.unite(cu,cv):
                total += w
        ans[qi] = total

    # 4) rebuild global edges[] with updated weights, then sort
    weight_map = {}
    for i in range(L,R):
        eid,newW = queries[i]
        weight_map[eid] = newW
    for idx in range(m):
        u,v,w,eid = edges[idx]
        edges[idx][2] = weight_map.get(eid, w)
    edges.sort(key=lambda e:e[2])
    for idx,e in enumerate(edges):
        pos[e[3]] = idx

# 5) output
print("\n".join(map(str,ans)))
```

Explanation Highlights:  
- We group queries into blocks to limit full-graph work to O(m α(m)) per block.  
- Within a block, only B edges change; most of the MST can be precomputed (the “baseline” on unchanged edges).  
- Contracting baseline components into super-nodes shrinks the problem: only ≲n edges plus B updates need reconsideration.  
- Each single‐edge update in the block can then be answered by rerunning Kruskal on O(n+B) edges in nearly-linear time.  
- Finally, updated edges are merged back into the global sorted array to prepare the next block.  
This yields an overall complexity roughly O((t/B)·m α(n) + t·(n+B) α(n) + (t/B)·(m+B)), which is efficient for n,m,t ≤ 4·10^4.