Problem:
Bridge Construction Planning
There is a city consisting of many small islands, and the citizens live in these islands.
Citizens feel inconvenience in requiring ferry rides between these islands.
The city mayor decided to build bridges connecting all the islands.
The city has two construction companies, A and B.
The mayor requested these companies for proposals, and obtained proposals in the form:
"Company A (or B) can build a bridge between islands
u
and
v
in
w
hundred million yen."
The mayor wants to accept some of these proposals to make a plan with the lowest budget.
However, if the mayor accepts too many proposals of one company,
the other may go bankrupt, which is not desirable for the city with only two construction companies.
However, on the other hand, to avoid criticism on wasteful construction,
the mayor can only accept the minimum number (i.e.,
n
− 1) of bridges for connecting all the islands.
Thus, the mayor made a decision that exactly
k
proposals by the company A
and exactly
n
− 1 −
k
proposals by the company B should be accepted.
Your task is to write a program that computes the cost of the plan with the lowest budget that satisfies the constraints.
Here, the cost of a plan means the sum of all the costs mentioned in the accepted proposals.
Input
The input consists of multiple datasets.
The number of datasets is at most 30.
Each dataset is in the following format.
n
m
k
u
1
v
1
w
1
l
1
...
u
m
v
m
w
m
l
m
The first line contains three integers
n
,
m
, and
k
, where
n
is the number of islands,
m
is the total number of proposals,
 and
k
is the number of proposals that are to be ordered to company A
(2 ≤
n
≤ 200, 1 ≤
m
≤ 600, and 0 ≤
k
≤
n
−1).
Islands are identified by integers, 1 through
n
.
The following
m
lines denote the proposals each of which is described with three integers
u
i
,
v
i
,
w
i
and one character
l
i
,
where
u
i
and
v
i
denote two bridged islands,
w
i
is the cost of the bridge (in hundred million yen),
and
l
i
is the name of the company that submits this proposal
(1 ≤
u
i
≤
n
, 1 ≤
v
i
≤
n
, 1 ≤
w
i
≤ 100, and
l
i
= 'A' or 'B').
You can assume that each bridge connects distinct islands, i.e.,
u
i
≠
v
i
,
and each company gives at most one proposal for each pair of islands, i.e., {
u
i
,
v
i
} ≠ {
u
j
,
v
j
} if
i
≠
j
and
l
i
=
l
j
.
The end of the input is indicated by a line with three zeros separated by single spaces.
Output
For each dataset, output a single line containing a single integer that 
denotes the cost (in hundred million yen) of the plan with the lowest 
budget.
If there are no plans that satisfy the constraints, output −1.
Sample Input
4 5 2
1 2 2 A
1 3 2 A
1 4 2 A
2 3 1 B
3 4 1 B
5 8 2
1 2 1 A
2 3 1 A
3 4 3 A
4 5 3 A
1 2 5 B
2 3 5 B
3 4 8 B
4 5 8 B
5 5 1
1 2 1 A
2 3 1 A
3 4 1 A
4 5 1 B
3 5 1 B
4 5 3
1 2 2 A
2 4 3 B
3 4 4 B
2 3 5 A
3 1 6 A
0 0 0
Output for the Sample Input
5
16
-1
-1

Submitted solutions:

code_snippet: /*

https://hitonanode.github.io/cplib-cpp/combinatorial_opt/test/matroid_intersection_dijkstra.aoj1605.test.cpp

edit by noya2

*/

#line 1 "combinatorial_opt/test/matroid_intersection_dijkstra.aoj1605.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1605"
#line 2 "combinatorial_opt/matroid_intersection_dijkstra.hpp"

#include <cassert>
#include <queue>
#include <vector>

// Find maximum weight size k + 1 intersection of two matroids using Dijkstra's algorithm
// Return `true` iff larger intersection is found.
// Complexity: O(Cn + nk log n) (C: circuit query)
template <class Matroid1, class Matroid2, class T = int>
bool augment_matroid_intersection_dijkstra(
    Matroid1 &m1,                 // Matroid, size n, updated
    Matroid2 &m2,                 // Matroid, size n, updated
    std::vector<bool> &I,         // Size k maximum weight intersection, size n, updated
    const std::vector<T> &weight, // Weights of elements, size n
    std::vector<T> &potential     // Potential, size n + 2, updated
) {
    const int n = I.size();

    assert((int)m1.size() == n);
    assert((int)m2.size() == n);
    assert((int)weight.size() == n);
    assert(potential.empty() or ((int)potential.size() == n) or ((int)potential.size() == n + 2));

    m1.set(I);
    m2.set(I);

    potential.resize(n + 2);

    auto l = [&](int e) -> T { return e < n ? (I.at(e) ? weight.at(e) : -weight.at(e)) : T(); };
    auto edge_len = [&](int s, int t) -> T { return l(t) - potential.at(t) + potential.at(s); };

    if (false) { // 自明な追加が可能かチェック（省略してもアルゴリズムは正当）
        int max_elem = -1;
        for (int e = 0; e < n; ++e) {
            if (!I.at(e) and (max_elem < 0 or weight.at(max_elem) < weight.at(e))) max_elem = e;
        }
        if (max_elem < 0) return false;
        for (int e = 0; e < n; ++e) {
            if (!I.at(e) and weight.at(e) == weight.at(max_elem) and m1.circuit(e).empty() and
                m2.circuit(e).empty()) {
                potential.at(e) -= l(e);
                I.at(e) = true;
                return true;
            }
        }
    }

    // Find minimum length (& minimum num. of vertices) gs-gt path
    const int gs = n, gt = n + 1;
    std::vector<std::vector<int>> to(gt + 1);

    bool has_gs_edge = false, has_gt_edge = false;

    for (int e = 0; e < n; ++e) {
        if (I.at(e)) continue;

        const auto c1 = m1.circuit(e), c2 = m2.circuit(e);

        if (c1.empty()) {
            to.at(e).push_back(gt);
            if (!has_gt_edge) {
                has_gt_edge = true;
                potential.at(gt) = potential.at(e);
            }
            if (T el = edge_len(e, gt); el < T()) potential.at(gt) += el;
        }
        for (int f : c1) {
            if (f != e) to.at(e).push_back(f);
        }

        if (c2.empty()) {
            to.at(gs).push_back(e);
            if (!has_gs_edge) {
                has_gs_edge = true;
                potential.at(gs) = potential.at(e) - l(e);
            }
            if (T el = edge_len(gs, e); el < T()) potential.at(gs) -= el;
        }
        for (int f : c2) {
            if (f != e) to.at(f).push_back(e);
        }
    }

    if (const T e0 = potential.at(gs); e0 != T()) {
        for (auto &p : potential) p -= e0;
    }

    if (!has_gs_edge or !has_gt_edge) return false;

    std::vector<bool> potential_fixed(gt + 1);

    T potential_add_unfixed_es = T();

    auto fix_potential = [&](int e) -> void {
        assert(!potential_fixed.at(e));
        potential_fixed.at(e) = true;
        potential.at(e) += potential_add_unfixed_es;
    };

    std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>, std::greater<>> pq;
    std::vector<T> dijkstra(gt + 1);
    std::vector<int> prv(gt + 1, -1);

    pq.emplace(T(), gs);

    // noya2 begin
    int many = 1001001;
    while (!pq.empty()){
        many--;
        assert(many > 0);
        auto [d, e] = pq.top(); pq.pop();
        if (potential_fixed[e]) continue;
        potential_fixed[e] = true;
        for (int ne : to[e]){
            if (potential_fixed[ne]) continue;
            auto len = edge_len(e, ne);
            assert(len >= T());
            auto nd = d + len;
            if (prv[ne] == -1 || nd < dijkstra[ne]){
                dijkstra[ne] = nd;
                prv[ne] = e;
                pq.emplace(dijkstra[ne], ne);
            }
        }
    }
    for (int i = 0; i < gt+1; i++){
        if (prv[i] == -1) continue;
        potential[i] = dijkstra[i] + potential[i] - potential[gs];
    }

    /*

    while (!pq.empty()) {
        const int e = pq.top().second;
        pq.pop();
        if (potential_fixed.at(e)) continue;
        if (e != gs) potential_add_unfixed_es = edge_len(prv.at(e), e);

        std::vector<std::pair<int, int>> push_cands;

        auto rec = [&](auto &&self, int cur) -> bool {
            if (cur == gt) return true;
            fix_potential(cur);

            for (int nxt : to.at(cur)) {
                if (potential_fixed.at(nxt)) continue;

                const T len = edge_len(cur, nxt) - potential_add_unfixed_es;
                // if (len < T()) std::cerr << cur << ' ' << nxt << ' ' << len << std::endl;
                assert(len >= T());

                if (len == T()) {
                    prv.at(nxt) = cur;
                    if (self(self, nxt)) return true;
                } else {
                    if (prv.at(nxt) == -1 or potential_add_unfixed_es + len < dijkstra.at(nxt)) {
                        dijkstra.at(nxt) = potential_add_unfixed_es + len;
                        prv.at(nxt) = cur;
                        push_cands.emplace_back(nxt, cur);
                    }
                }
            }
            return false;
        };
        if (rec(rec, e)) break;

        for (auto [nxt, now] : push_cands) {
            if (prv.at(nxt) == now) pq.emplace(dijkstra.at(nxt), nxt);
        }
    }

    for (int e = 0; e < gt + 1; ++e) {
        if (!potential_fixed.at(e)) fix_potential(e);
    }
    */

    // noya2 end

    if (prv.at(gt) < 0) return false;

    prv.assign(gt + 1, -1);
    std::queue<int> q;
    q.push(gs);

    for (int now = q.front(); now != gt; now = q.front()) {
        q.pop();
        for (int nxt : to.at(now)) {
            if (prv[nxt] == -1 && potential[now] + l(nxt) == potential[nxt]){ // noya2
            // if (prv.at(nxt) == -1 and edge_len(now, nxt) == T()) { // noya2
                prv.at(nxt) = now;
                q.push(nxt);
            }
        }
    }

    for (int e = prv.at(gt); e != gs; e = prv.at(e)) {
        potential.at(e) -= l(e);
        I.at(e) = !I.at(e);
    }

    return true;
}
#line 3 "combinatorial_opt/matroids/graphic_matroid.hpp"
#include <utility>
#line 5 "combinatorial_opt/matroids/graphic_matroid.hpp"

// GraphicMatroid: subgraph of undirected graphs, without loops
class GraphicMatroid {
    using Vertex = int;
    using Element = int;
    int M;
    int V; // # of vertices of graph
    std::vector<std::vector<std::pair<Vertex, Element>>> to;
    std::vector<std::pair<Vertex, Vertex>> edges;
    std::vector<Element> backtrack;
    std::vector<Vertex> vprev;
    std::vector<int> depth, root;

public:
    GraphicMatroid(int V, const std::vector<std::pair<Vertex, Vertex>> &edges_)
        : M(edges_.size()), V(V), to(V), edges(edges_) {
        for (int e = 0; e < int(edges_.size()); e++) {
            int u = edges_[e].first, v = edges_[e].second;
            assert(0 <= u and u < V);
            assert(0 <= v and v < V);
            if (u != v) {
                to[u].emplace_back(v, e);
                to[v].emplace_back(u, e);
            }
        }
    }
    int size() const { return M; }

    std::vector<Vertex> que;
    template <class State> void set(State I) {
        assert(int(I.size()) == M);
        backtrack.assign(V, -1);
        vprev.assign(V, -1);
        depth.assign(V, -1);
        root.assign(V, -1);
        que.resize(V);
        int qb = 0, qe = 0;
        for (Vertex i = 0; i < V; i++) {
            if (backtrack[i] >= 0) continue;
            que[qb = 0] = i, qe = 1, depth[i] = 0;
            while (qb < qe) {
                Vertex now = que[qb++];
                root[now] = i;
                for (auto nxt : to[now]) {
                    if (depth[nxt.first] < 0 and I[nxt.second]) {
                        backtrack[nxt.first] = nxt.second;
                        vprev[nxt.first] = now;
                        depth[nxt.first] = depth[now] + 1;
                        que[qe++] = nxt.first;
                    }
                }
            }
        }
    }

    std::vector<Element> circuit(const Element e) const {
        assert(0 <= e and e < M);
        Vertex s = edges[e].first, t = edges[e].second;
        if (root[s] != root[t]) return {};
        std::vector<Element> ret{e};
        auto step = [&](Vertex &i) { ret.push_back(backtrack[i]), i = vprev[i]; };
        int ddepth = depth[s] - depth[t];
        for (; ddepth > 0; --ddepth) step(s);
        for (; ddepth < 0; ++ddepth) step(t);
        while (s != t) step(s), step(t);
        return ret;
    }
};
#line 4 "combinatorial_opt/matroids/partition_matroid.hpp"

// Partition matroid (partitional matroid) : direct sum of uniform matroids
class PartitionMatroid {
    using Element = int;
    int M;
    std::vector<std::vector<Element>> parts;
    std::vector<int> belong;
    std::vector<int> R;
    std::vector<int> cnt;
    std::vector<std::vector<Element>> circuits;

public:
    // parts: partition of [0, 1, ..., M - 1]
    // R: only R[i] elements from parts[i] can be chosen for each i.
    PartitionMatroid(int M, const std::vector<std::vector<int>> &parts_, const std::vector<int> &R_)
        : M(M), parts(parts_), belong(M, -1), R(R_) {
        assert(parts.size() == R.size());
        for (int i = 0; i < int(parts.size()); i++) {
            for (Element e : parts[i]) belong[e] = i;
        }
        for (Element e = 0; e < M; e++) {
            // assert(belong[e] != -1);
            if (belong[e] == -1) {
                belong[e] = parts.size();
                parts.push_back({e});
                R.push_back(1);
            }
        }
    }
    int size() const { return M; }

    template <class State> void set(const State &I) {
        cnt = R;
        for (int e = 0; e < M; e++) {
            if (I[e]) cnt[belong[e]]--;
        }
        circuits.assign(cnt.size(), {});
        for (int e = 0; e < M; e++) {
            if (I[e] and cnt[belong[e]] == 0) circuits[belong[e]].push_back(e);
        }
    }

    std::vector<Element> circuit(const Element e) const {
        assert(0 <= e and e < M);
        int p = belong[e];
        if (cnt[p] == 0) {
            auto ret = circuits[p];
            ret.push_back(e);
            return ret;
        }
        return {};
    }
};
#line 5 "combinatorial_opt/test/matroid_intersection_dijkstra.aoj1605.test.cpp"
#include <iostream>
#include <numeric>
#line 9 "combinatorial_opt/test/matroid_intersection_dijkstra.aoj1605.test.cpp"
using namespace std;

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    while (true) {
        int N, M, K;
        cin >> N >> M >> K;
        if (N == 0) break;
        vector<vector<int>> partition(2);
        vector<int> R{K, N - 1 - K};
        vector<pair<int, int>> edges;
        vector<int> weight;
        for (int e = 0; e < M; ++e) {
            int u, v, w;
            char l;
            cin >> u >> v >> w >> l;
            --u, --v;
            partition[l == 'B'].push_back(e);
            edges.emplace_back(u, v);
            weight.push_back(-w);
        }
        PartitionMatroid M1(edges.size(), partition, R);
        GraphicMatroid M2(N, edges);

        vector<int> potential(weight.size());
        vector<bool> ret(weight.size());
        while (augment_matroid_intersection_dijkstra(M1, M2, ret, weight, potential)) continue;
        int ne = accumulate(ret.begin(), ret.end(), 0);
        if (ne < N - 1) {
            cout << "-1\n";
        } else {
            int sum = 0;
            for (int e = 0; e < M; ++e) sum -= ret.at(e) * weight.at(e);
            cout << sum << '\n';
        }
    }
}
accuracy: 1
time_ms: 360
memory_kb: 3744
final_rank: 15

code_snippet: // AOJ #1605 Bridge Construction Planning
// 2025.2.15

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct DSU {
    vector<int> parent, rank;
    DSU(int n) : parent(n), rank(n,0) {
        for(int i = 0; i < n; i++){
            parent[i] = i;
        }
    }
    int findp(int a) {
        return parent[a] == a ? a : parent[a] = findp(parent[a]);
    }
    bool unite(int a, int b) {
        a = findp(a), b = findp(b);
        if(a == b) return false;
        if(rank[a] < rank[b]) swap(a, b);
        parent[b] = a;
        if(rank[a] == rank[b]) rank[a]++;
        return true;
    }
};
 
struct Edge {
    int u, v;
    int cost;
    bool isA;
    int idx;
};
 
struct MSTResult {
    bool valid;
    int redCount;
    ll origCost;
};
 
MSTResult computeMST(int n, const vector<Edge>& edges, int lambda) {
    int m = edges.size();
    vector<Edge> sortedEdges = edges;
    auto cmp = [lambda](const Edge &a, const Edge &b) {
        int wa = a.cost + (a.isA ? lambda : 0);
        int wb = b.cost + (b.isA ? lambda : 0);
        if(wa != wb) return wa < wb;
        return a.idx < b.idx;
    };
    sort(sortedEdges.begin(), sortedEdges.end(), cmp);
 
    DSU dsu(n);
    int edgeCount = 0;
    int redCount = 0;
    ll sumOrig = 0;
    for (int i = 0; i < m && edgeCount < n - 1; i++){
        int u = sortedEdges[i].u - 1;
        int v = sortedEdges[i].v - 1;
        if(dsu.unite(u, v)){
            edgeCount++;
            sumOrig += sortedEdges[i].cost;
            if(sortedEdges[i].isA) redCount++;
        }
    }
    MSTResult res;
    res.valid = (edgeCount == n - 1);
    res.redCount = res.valid ? redCount : -1;
    res.origCost = res.valid ? sumOrig : -1;
    return res;
}
 
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
 
    while(true){
        int n, m, k;
        cin >> n >> m >> k;
        if(n == 0) break;
 
        vector<Edge> edges;
        edges.reserve(m);
        for (int i = 0; i < m; i++){
            int u, v, w;
            char comp;
            cin >> u >> v >> w >> comp;
            Edge e;
            e.u = u; e.v = v; e.cost = w;
            e.isA = (comp == 'A');
            e.idx = i;
            edges.push_back(e);
        }
 
        int lambdaLow = -1000, lambdaHigh = 1000;
        MSTResult resLow = computeMST(n, edges, lambdaLow);
        MSTResult resHigh = computeMST(n, edges, lambdaHigh);
        if(!resLow.valid || !resHigh.valid){
            cout << -1 << "\n";
            continue;
        }
        int maxRed = resLow.redCount;
        int minRed = resHigh.redCount;
 
        if(k < minRed || k > maxRed){
            cout << -1 << endl;
            continue;
        }
 
        ll best = -LLONG_MAX;
        for (int lambda = lambdaLow; lambda <= lambdaHigh; lambda++){
            MSTResult cur = computeMST(n, edges, lambda);
            if(!cur.valid) continue;
            ll candidate = cur.origCost + (ll)lambda * (cur.redCount - k);
            best = max(best, candidate);
        }
 
        cout << best << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 380
memory_kb: 3424
final_rank: 13

code_snippet: #include<iostream>
#include<algorithm>
template<typename T=int>
struct Edge{
  int from,to;
  T weight;
  int index;
  Edge(int from_,int to_,T weight_=T(),int index_=-1):from(from_),to(to_),weight(weight_),index(index_){}
  Edge():from(-1),to(-1),weight(),index(-1){}
  friend std::ostream &operator<<(std::ostream &os,const Edge&e){
    os<<'[';
    os<<"from:"<<e.from;
    os<<"to:"<<e.to;
    os<<"weight:"<<e.weight;
    os<<"index:"<<e.index;
    os<<']';
    return os;
  }
};
#include<vector>
template<typename T=int>
struct Graph{
private:
  int n;
  std::vector<Edge<T>>edge;
  std::vector<Edge<T>>g;
  std::vector<int>ptr;
  bool directed;
  struct graph_range{
    using iterator=typename std::vector<Edge<T>>::iterator;
    iterator l,r;
    iterator begin()const{return l;}
    iterator end()const{return r;}
    int size()const{return r-l;}
    Edge<T> &operator[](int i)const{return l[i];}
  };
  struct const_graph_range{
    using iterator=typename std::vector<Edge<T>>::const_iterator;
    iterator l,r;
    iterator begin()const{return l;}
    iterator end()const{return r;}
    int size()const{return r-l;}
    const Edge<T> &operator[](int i)const{return l[i];}
  };
public:
  Graph(int n_,bool dir_):n(n_),directed(dir_){}
  Graph():n(0){}
  Graph(int n_,bool dir_,const std::vector<Edge<T>>&e):n(n_),directed(dir_),edge(e){build();}
  template<bool weighted=false,bool index=1>
  void read(int m){
    edge.reserve(m);
    for(int i=0;i<m;i++){
      int u,v;
      std::cin>>u>>v;
      T w;
      if constexpr(index)u--,v--;
      if constexpr(weighted)std::cin>>w;
      else w=1;
      edge.emplace_back(u,v,w,i);
    }
    build();
  }
  void add_edge(int u,int v){
    int id=edge.size();
    edge.emplace_back(u,v,1,id);
  }
  void add_edge(int u,int v,T w){
    int id=edge.size();
    edge.emplace_back(u,v,w,id);
  }
  void add_edge(int u,int v,T w,int index){
    edge.emplace_back(u,v,w,index);
  }
  void build(){
    std::vector<int>cnt(n+1,0);
    for(const Edge<T>&e:edge){
      cnt[e.from+1]++;
      if(!directed)cnt[e.to+1]++;
    }
    for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1];
    ptr=cnt;
    g.resize(cnt[n]);
    for(const Edge<T>&e:edge){
      g[cnt[e.from]++]=e;
      if(!directed)g[cnt[e.to]++]=Edge<T>(e.to,e.from,e.weight,e.index);
    }
  }
  void reverse(){
    if(directed){
      for(Edge<T>&e:edge)swap(e.from,e.to);
      build();
    }
  }
  inline void to_directed(){
    directed=true;
    build();
  }
  inline void to_undirected(){
    directed=false;
    build();
  }
  void reserve(int m){edge.reserve(m);}
  graph_range operator[](int i){return graph_range{g.begin()+ptr[i],g.begin()+ptr[i+1]};}
  const_graph_range operator[](int i)const{return const_graph_range{g.begin()+ptr[i],g.begin()+ptr[i+1]};}
  const Edge<T>& get_edge(int i)const{return edge[i];}
  inline bool is_directed()const{return directed;}
  inline int size()const{return n;}
  inline int edge_size()const{return edge.size();}
  typename std::vector<Edge<T>>::iterator begin(){return edge.begin();}
  typename std::vector<Edge<T>>::iterator end(){return edge.end();}
  typename std::vector<Edge<T>>::const_iterator begin()const{return edge.begin();}
  typename std::vector<Edge<T>>::const_iterator end()const{return edge.end();}
};
struct GraphicMatroid{
private:
  Graph<>g;
  std::vector<std::pair<int,int>>pre;
  std::vector<int>que,dst,root;
  int p,q;
public:
  GraphicMatroid(const Graph<>&g_):g(g_),pre(g_.edge_size()),que(g_.edge_size()),dst(g_.size()),root(g_.size()){}
  int size()const{return g.edge_size();}
  void set(const std::vector<bool>&I){
    std::fill(pre.begin(),pre.end(),std::make_pair(-1,-1));
    for(int i=0;i<g.size();i++){
      if(pre[i].first==-1){
        for(p=q=0,que[q++]=i,dst[i]=0;p<q;){
          int x=que[p++];
          root[x]=i;
          for(const Edge<>&e:g[x])if(I[e.index]&&pre[e.to].first==-1){
            pre[e.to]=std::make_pair(e.from,e.index);
            dst[e.to]=dst[e.from]+1;
            que[q++]=e.to;
          }
        }
      }
    }
  }
  std::vector<int>circuit(int x)const{
    const Edge<>&e=g.get_edge(x);
    if(root[e.from]!=root[e.to])return {};
    std::vector<int>res;
    int u=e.from,v=e.to;
    if(dst[u]>dst[v])std::swap(u,v);
    while(dst[u]<dst[v])res.push_back(pre[v].second),v=pre[v].first;
    while(u!=v){
      res.push_back(pre[u].second),u=pre[u].first;
      res.push_back(pre[v].second),v=pre[v].first;
    }
    return res;
  }
};
struct PartitionMatroid{
private:
  int n;
  std::vector<std::vector<int>>s;
  std::vector<int>belong;
  std::vector<int>c,c2;
  std::vector<std::vector<int>>circuits;
public:
  PartitionMatroid(int n_,const std::vector<std::vector<int>>&s_,const std::vector<int>&c_):n(n_),s(s_),belong(n,-1),c2(c_){
    for(int i=0;i<(int)s.size();i++){
      for(int j:s[i])belong[j]=i;
    }
    for(int i=0;i<n;i++)if(belong[i]==-1){
      belong[i]=s.size();
      s.push_back({i});
      c2.push_back(1);
    }
    circuits.resize(s.size());
  }
  int size()const{return n;}
  void set(const std::vector<bool>&I){
    c=c2;
    for(int i=0;i<n;i++)if(I[i])c[belong[i]]--;
    for(int i=0;i<(int)circuits.size();i++)circuits[i].clear();
    for(int i=0;i<n;i++)if(I[i]&&c[belong[i]]==0)circuits[belong[i]].push_back(i);
  }
  std::vector<int>circuit(int x)const{
    if(c[belong[x]]==0){
      std::vector<int>res=circuits[belong[x]];
      res.push_back(x);
      return res;
    }
    return {};
  }
};
#include<cassert>
#include<limits>
#include<numeric>
template<typename T>
std::pair<std::vector<T>,std::vector<int>>shortest_path_faster_algorithm(const Graph<T>&g,int s=0){
  static constexpr T inf=std::numeric_limits<T>::max();
  static constexpr T minf=std::numeric_limits<T>::min();
  int n=g.size();
  std::vector<T>dst(n,inf);
  std::vector<int>pre(n,-1);
  dst[s]=0;
  std::vector<int>que(n+1);
  int p=0,q=0;
  std::vector<int>time(n,0);
  std::vector<bool>contain(n,false);
  que[q++]=s;
  contain[s]=true;
  while(p!=q){
    int x=que[p++];
    if(p==n+1)p=0;
    contain[x]=false;
    for(const Edge<T>&e:g[x]){
      T cost=dst[x]+e.weight;
      if(dst[e.to]>cost){
        dst[e.to]=cost;
        pre[e.to]=e.from;
        if(!contain[e.to]){
          if(++time[e.to]>=n)continue;
          contain[e.to]=true;
          que[q++]=e.to;
          if(q==n+1)q=0;
        }
      }
    }
  }
  std::fill(contain.begin(),contain.end(),false);
  p=q=0;
  for(int i=0;i<n;i++)for(const Edge<T>&e:g[i])if(dst[i]!=inf&&e.from==e.to&&e.weight<0)time[i]=n;
  for(int i=0;i<n;i++)if(time[i]>=n){
    que[q++]=i;
    contain[i]=true;
  }
  while(p!=q){
    int x=que[p++];
    dst[x]=minf;
    if(p==n+1)p=0;
    for(const Edge<T>&e:g[x])if(!contain[e.to]){
      contain[e.to]=true;
      que[q++]=e.to;
      if(q==n+1)q=0;
    }
  }
  return std::make_pair(dst,pre);
}
template<typename M1,typename M2,typename W>
std::vector<bool>matroid_intersection(M1 m1,M2 m2,std::vector<W>weight={}){
  static constexpr W inf=std::numeric_limits<W>::max();
  assert(m1.size()==m2.size());
  assert(weight.empty()||(int)weight.size()==m1.size());
  int n=m1.size();
  if(weight.empty())weight=std::vector<W>(n,0);
  std::vector<bool>res(n,false);
  while(true){
    Graph<W>g(n+2,true);
    m1.set(res),m2.set(res);
    for(int i=0;i<n;i++)if(!res[i]){
      std::vector<int>c1=m1.circuit(i),c2=m2.circuit(i);
      if(c1.empty())g.add_edge(i,n+1,0);
      for(int j:c1)if(i!=j)g.add_edge(i,j,-weight[j]*(n+1)+1);
      if(c2.empty())g.add_edge(n,i,weight[i]*(n+1)+1);
      for(int j:c2)if(i!=j)g.add_edge(j,i,weight[i]*(n+1)+1);
    }
    g.build();
    auto [dst,pre]=shortest_path_faster_algorithm(g,n);
    if(dst[n+1]==inf)break;
    for(int i=pre[n+1];i!=n;i=pre[i])res[i]=!res[i];
  }
  return res;
}
using namespace std;
int main(){
  int n,m,k;
  while(true){
    cin>>n>>m>>k;
    if(n==0)break;
    Graph<>g(n,false);
    vector<int>weight(m);
    vector<vector<int>>b(2);
    for(int i=0;i<m;i++){
      int u,v,w;
      char c;
      cin>>u>>v>>w>>c;
      u--,v--;
      g.add_edge(u,v);
      weight[i]=w;
      b[c=='B'].push_back(i);
    }
    g.build();
    GraphicMatroid gm(g);
    PartitionMatroid pm(m,b,{k,n-1-k});
    auto ans=matroid_intersection(gm,pm,weight);
    int sum=0;
    for(int i=0;i<m;i++)if(ans[i])sum+=weight[i],n--;
    if(n==1)cout<<sum<<'\n';
    else cout<<"-1\n";
  }
}
accuracy: 1
time_ms: 340
memory_kb: 4804
final_rank: 18

code_snippet: #include<bits/stdc++.h>
// #include<atcoder/all>
// #include<boost/multiprecision/cpp_int.hpp>

using namespace std;
// using namespace atcoder;
// using bint = boost::multiprecision::cpp_int;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<ll,ll>;
using vi = vector<ll>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using ve = vector<vector<int>>;
using vb = vector<bool>;
using vvb = vector<vb>;
#define rep(i,n) for(ll i = 0;i < (ll)n;i++)
#define ALL(x) (x).begin(),(x).end()
#define sz(c) ((ll)(c).size())
#define LB(A,x) (int)(lower_bound(A.begin(),A.end(),x)-A.begin())
#define UB(A,x) (int)(upper_bound(A.begin(),A.end(),x)-A.begin())
// #define MOD 1000000007
#define MOD 998244353
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){for(int i = 0;i < v.size();i++)os<<v[i]<<(i+1!=v.size()?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.first<<" "<<p.second;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T> inline bool chmax(T &a,T b){if(a < b){a = b;return true;}return false;}
template<typename T> inline bool chmin(T &a,T b){if(a > b){a = b;return true;}return false;}
ld dist(ld x1,ld y1,ld x2, ld y2){return sqrtl((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}

// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/matroid_example.hpp
// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/graphic_matroid.hpp
// GraphicMatroid: subgraph of undirected graphs, without loops
class GraphicMatroid{
  using Vertex = int;
  using Element = int;
  int M;
  int n; // # of vertices of graph
  vector<vector<pair<Vertex,Element>>> to; //{行先、辺番号}
  vector<pair<Vertex,Vertex>> edges; 
  vector<Element> backtrack;
  vector<Vertex> vprev;
  vector<int> dep,root;

  public:
  GraphicMatroid(int n,const vector<pair<Vertex,Vertex>> &edges_)
    : M(edges_.size()),n(n),to(n),edges(edges_){
    for(int e = 0;e < int(edges_.size());e++){
      int u = edges_[e].first,v = edges_[e].second;
      assert(0 <= u && u < n);
      assert(0 <= v && v < n);
      if(u != v){
        to[u].emplace_back(v,e);
        to[v].emplace_back(u,e);
      }
    }
  }
  int size()const{return M;}

  vector<Vertex> que;
  // O(size of matroid)
  template<class State = vector<bool>> void set(State I){
    assert(int(I.size()) == M);
    backtrack.assign(n,-1);
    vprev.assign(n,-1);
    dep.assign(n,-1);
    root.assign(n,-1);
    que.resize(n);
    int qb = 0,qe = 0;
    for(Vertex i = 0;i < n;i++){
      if(backtrack[i] >= 0)continue;
      que[qb = 0] = i;qe = 1,dep[i] = 0;
      while(qb < qe){
        Vertex ov = que[qb++];
        root[ov] = i;
        for(auto [nv,nidx] : to[ov]){
          if(dep[nv] < 0 && I[nidx]){
            backtrack[nv] = nidx;
            vprev[nv] = ov;
            dep[nv] = dep[ov] + 1;
            que[qe++] = nv;
          }
        }
      }
    }
  }

  // 閉路が順番に出力されるわけではない。O(size of independent set)
  vector<Element> circuit(const Element e)const{
    assert(0 <= e && e < M);
    Vertex s = edges[e].first,t = edges[e].second;
    if(root[s] != root[t])return {};
    vector<Element> res{e};
    auto step = [&](Vertex &i){res.emplace_back(backtrack[i]),i = vprev[i];};
    int dep_diff = dep[s] - dep[t];
    for(;dep_diff > 0;--dep_diff)step(s);
    for(;dep_diff < 0;++dep_diff)step(t);
    while(s != t)step(s),step(t);
    return res;
  }
};


// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/matroid_example.hpp
// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/partition_matroid.hpp
// Partition matroid (partitional matroid) : direct sum of uniform matroids
class PartitionMatroid{
  using Element = int;
  int M;
  vector<vector<Element>> parts;
  vector<int> belong;
  vector<int> R;
  vector<int> cnt;
  vector<vector<Element>> circuits;

  public:
  // parts: partition of [0, 1, ..., M - 1]
  // R: only R[i] elements from parts[i] can be chosen for each i.
  PartitionMatroid(int M,const vector<vector<Element>> &parts_,const vector<int> &R_)
    : M(M),parts(parts_),belong(M,-1),R(R_) {
    assert(parts.size() == R.size());
    for(int i = 0;i < int(parts.size());i++){
      for(Element e : parts[i])belong[e] = i;
    }
    for(Element e = 0;e < M;e++){
      if(belong[e] == -1){
        belong[e] = parts.size();
        parts.push_back({e});
        R.emplace_back(1);
      }
    }
  }
  int size() const {return M;}

  // O(size of matroid)
  template<class State = vector<bool>>
  void set(const State &I){
    cnt = R;
    for(int e = 0;e < M;e++){
      if(I[e])cnt[belong[e]]--;
    }
    circuits.assign(cnt.size(),{});
    for(int e = 0;e < M;e++){
      if(I[e] && cnt[belong[e]] == 0)circuits[belong[e]].emplace_back(e);
    }
  }
  // O(size of independent set)
  vector<Element> circuit(const Element e)const{
    assert(0 <= e && e < M);
    int p = belong[e];
    if(cnt[p] == 0){
      auto res = circuits[p];
      res.emplace_back(e);
      return res;
    }
    return {};
  }
};



// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroid_intersection.hpp.html
// http://dopal.cs.uec.ac.jp/okamotoy/lect/2015/matroid/
// ``重み付き！！！``重み付き！！！``重み付き！！！``重み付き！！！``重み付き！！！``重み付き！！！
// m1, m2: matroids
// I: independent set (will be updated if augmenting path is found)
// Return `true` iff augmenting path is found.
// Complexity: O(Cn + n^2) (C: circuit query,n:matroid台集合の要素数)
template<class Matroid1,class Matroid2,class T = int>
bool matroid_intersection_augment(Matroid1 &m1,Matroid2 &m2,vector<bool> &I,const vector<T> &weights){
  const int n = m1.size();
  assert(m2.size() == n);
  assert((int)I.size() == n);

  const int gs = n,gt = n+1;
  const T INVALID = numeric_limits<T>::max();
  vector<tuple<int,int,T>> v;
  m1.set(I);
  m2.set(I);
  // 補助グラフの作成 O(nC + n^2)
  for(int e = 0;e < n;e++){
    if(I[e])continue;
    auto c1 = m1.circuit(e),c2 = m2.circuit(e);
    if(c1.empty())v.emplace_back(e,gt,T());
    for(auto f : c1)if(f != e)v.emplace_back(e,f,-weights[f]);
    if(c2.empty())v.emplace_back(gs,e,weights[e]);
    for(auto f : c2)if(f != e)v.emplace_back(f,e,weights[e]);
  }
  // 最短経路 Bellman-ford O(n^3)
  vector<T> dist(n+2,INVALID);
  vector<T> prev(n+2,INVALID);
  dist[gs] = 0;
  for(int _ = 0;_ < n+2;_++){ // 今、頂点数は n+2
    bool changed = false;
    for(auto &[ov,nv,wei] : v){
      if(dist[ov] == INVALID)continue;
      if(dist[nv] > dist[ov] + wei){
        dist[nv] = dist[ov] + wei;
        prev[nv] = ov;
        changed = true;
      }
    }
    if(!changed)break;
  }// 負閉路はそんざいしない(はず)
  
  // 経路復元。増加路実行
  if(dist[gt] == INVALID)return false;
  int now_vertex = gt;
  while(prev[now_vertex] != INVALID){
    now_vertex = prev[now_vertex];
    if(now_vertex != gs && now_vertex != gt)I[now_vertex] = !I[now_vertex];
  }
  return true;
}

// Minimum weight matroid intersection solver
// Complexity: O(Cn^2 + n^4) (C : circuit query)
template <class Matroid1, class Matroid2, class T = int>
vector<bool> MatroidIntersection(Matroid1 matroid1,Matroid2 matroid2,vector<T> &weights){
  const int n = matroid1.size();
  assert(matroid2.size() == n);
  assert(weights.size() == n);
  
  vector<bool> I(n);
  while(matroid_intersection_augment(matroid1,matroid2,I,weights));
  return I;
}
int main(){
  
  ios_base::sync_with_stdio(0), cin.tie(0);
  while(1){
    int n,m,K;cin >> n >> m >> K;
    if(!n)break;
    ve parts(2);
    vector<int> R{K,n-K-1};
    vector<pair<int,int>> edge;
    vi weight;
    rep(i,m){
      int u,v,w;char l;cin >> u >> v >> w >> l;
      u--;v--;
      edge.emplace_back(u,v);
      parts[l-'A'].emplace_back(i);
      weight.emplace_back(w);
    }
    GraphicMatroid gm(n,edge);
    PartitionMatroid pm(m,parts,R);
    vb I = MatroidIntersection(gm,pm,weight);
    int cnt = accumulate(ALL(I),0);
    if(cnt != n-1)cout << "-1\n";
    else{
      int res = 0;
      rep(e,m)res += I[e]*weight[e];
      cout << res << "\n";
    }
  }
  

  return 0;
}
accuracy: 1
time_ms: 260
memory_kb: 4988
final_rank: 14

code_snippet: #include<bits/stdc++.h>
// #include<atcoder/all>
// #include<boost/multiprecision/cpp_int.hpp>

using namespace std;
// using namespace atcoder;
// using bint = boost::multiprecision::cpp_int;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<ll,ll>;
using vi = vector<ll>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using ve = vector<vector<int>>;
using vb = vector<bool>;
using vvb = vector<vb>;
#define rep(i,n) for(ll i = 0;i < (ll)n;i++)
#define ALL(x) (x).begin(),(x).end()
#define sz(c) ((ll)(c).size())
#define LB(A,x) (int)(lower_bound(A.begin(),A.end(),x)-A.begin())
#define UB(A,x) (int)(upper_bound(A.begin(),A.end(),x)-A.begin())
// #define MOD 1000000007
#define MOD 998244353
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){for(int i = 0;i < v.size();i++)os<<v[i]<<(i+1!=v.size()?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.first<<" "<<p.second;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T> inline bool chmax(T &a,T b){if(a < b){a = b;return true;}return false;}
template<typename T> inline bool chmin(T &a,T b){if(a > b){a = b;return true;}return false;}
ld dist(ld x1,ld y1,ld x2, ld y2){return sqrtl((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}

// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/matroid_example.hpp
// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/graphic_matroid.hpp
// GraphicMatroid: subgraph of undirected graphs, without loops
class GraphicMatroid{
  using Vertex = int;
  using Element = int;
  int M;
  int n; // # of vertices of graph
  vector<vector<pair<Vertex,Element>>> to; //{行先、辺番号}
  vector<pair<Vertex,Vertex>> edges; 
  vector<Element> backtrack;
  vector<Vertex> vprev;
  vector<int> dep,root;

  public:
  GraphicMatroid(int n,const vector<pair<Vertex,Vertex>> &edges_)
    : M(edges_.size()),n(n),to(n),edges(edges_){
    for(int e = 0;e < int(edges_.size());e++){
      int u = edges_[e].first,v = edges_[e].second;
      assert(0 <= u && u < n);
      assert(0 <= v && v < n);
      if(u != v){
        to[u].emplace_back(v,e);
        to[v].emplace_back(u,e);
      }
    }
  }
  int size()const{return M;}

  vector<Vertex> que;
  // O(size of matroid)
  template<class State = vector<bool>> void set(State I){
    assert(int(I.size()) == M);
    backtrack.assign(n,-1);
    vprev.assign(n,-1);
    dep.assign(n,-1);
    root.assign(n,-1);
    que.resize(n);
    int qb = 0,qe = 0;
    for(Vertex i = 0;i < n;i++){
      if(backtrack[i] >= 0)continue;
      que[qb = 0] = i;qe = 1,dep[i] = 0;
      while(qb < qe){
        Vertex ov = que[qb++];
        root[ov] = i;
        for(auto [nv,nidx] : to[ov]){
          if(dep[nv] < 0 && I[nidx]){
            backtrack[nv] = nidx;
            vprev[nv] = ov;
            dep[nv] = dep[ov] + 1;
            que[qe++] = nv;
          }
        }
      }
    }
  }

  // 閉路が順番に出力されるわけではない。O(size of independent set)
  vector<Element> circuit(const Element e)const{
    assert(0 <= e && e < M);
    Vertex s = edges[e].first,t = edges[e].second;
    if(root[s] != root[t])return {};
    vector<Element> res{e};
    auto step = [&](Vertex &i){res.emplace_back(backtrack[i]),i = vprev[i];};
    int dep_diff = dep[s] - dep[t];
    for(;dep_diff > 0;--dep_diff)step(s);
    for(;dep_diff < 0;++dep_diff)step(t);
    while(s != t)step(s),step(t);
    return res;
  }
};


// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/matroid_example.hpp
// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroids/partition_matroid.hpp
// Partition matroid (partitional matroid) : direct sum of uniform matroids
class PartitionMatroid{
  using Element = int;
  int M;
  vector<vector<Element>> parts;
  vector<int> belong;
  vector<int> R;
  vector<int> cnt;
  vector<vector<Element>> circuits;

  public:
  // parts: partition of [0, 1, ..., M - 1]
  // R: only R[i] elements from parts[i] can be chosen for each i.
  PartitionMatroid(int M,const vector<vector<Element>> &parts_,const vector<int> &R_)
    : M(M),parts(parts_),belong(M,-1),R(R_) {
    assert(parts.size() == R.size());
    for(int i = 0;i < int(parts.size());i++){
      for(Element e : parts[i])belong[e] = i;
    }
    for(Element e = 0;e < M;e++){
      if(belong[e] == -1){
        belong[e] = parts.size();
        parts.push_back({e});
        R.emplace_back(1);
      }
    }
  }
  int size() const {return M;}

  // O(size of matroid)
  template<class State = vector<bool>>
  void set(const State &I){
    cnt = R;
    for(int e = 0;e < M;e++){
      if(I[e])cnt[belong[e]]--;
    }
    circuits.assign(cnt.size(),{});
    for(int e = 0;e < M;e++){
      if(I[e] && cnt[belong[e]] == 0)circuits[belong[e]].emplace_back(e);
    }
  }
  // O(size of independent set)
  vector<Element> circuit(const Element e)const{
    assert(0 <= e && e < M);
    int p = belong[e];
    if(cnt[p] == 0){
      auto res = circuits[p];
      res.emplace_back(e);
      return res;
    }
    return {};
  }
};


// https://hitonanode.github.io/cplib-cpp/combinatorial_opt/matroid_intersection.hpp.html
// http://dopal.cs.uec.ac.jp/okamotoy/lect/2015/matroid/
// ``重み付き！！！``重み付き！！！``重み付き！！！``重み付き！！！``重み付き！！！``重み付き！！！
// m1, m2: matroids
// I: independent set (will be updated if augmenting path is found)
// Return `true` iff augmenting path is found.
// Complexity: O(Cn + n^2) (C: circuit query,n:matroid台集合の要素数)
template<class Matroid1,class Matroid2,class T = int>
bool matroid_intersection_augment(Matroid1 &m1,Matroid2 &m2,vector<bool> &I,const vector<T> &weights){
  const int n = m1.size();
  assert(m2.size() == n);
  assert((int)I.size() == n);

  // auto weight = [&](int e){return weights.empty() ? T() : weights[e]*(n+1);};

  const int gs = n,gt = n+1;
  const T INVALID = numeric_limits<T>::max();
  vector<tuple<int,int,T>> v(n+2);
  m1.set(I);
  m2.set(I);
  // 補助グラフの作成 O(nC + n^2)
  for(int e = 0;e < n;e++){
    if(I[e])continue;
    auto c1 = m1.circuit(e),c2 = m2.circuit(e);
    if(c1.empty())v.emplace_back(e,gt,T());
    for(auto f : c1)if(f != e)v.emplace_back(e,f,-weights[f]);
    if(c2.empty())v.emplace_back(gs,e,weights[e]);
    for(auto f : c2)if(f != e)v.emplace_back(f,e,weights[e]);
  }
  // 最短経路 Bellman-ford O(n^3)
  vector<T> dist(n+2,INVALID);
  vector<T> prev(n+2,INVALID);
  dist[gs] = 0;
  for(int _ = 0;_ < n+2;_++){ // 今、頂点数は n+2
    bool changed = false;
    for(auto &[ov,nv,wei] : v){
      if(dist[ov] == INVALID)continue;
      if(dist[nv] > dist[ov] + wei){
        dist[nv] = dist[ov] + wei;
        prev[nv] = ov;
        changed = true;
      }
    }
    if(!changed)break;
  }// 負閉路はそんざいしない(はず)
  
  // 経路復元。増加路実行
  if(dist[gt] == INVALID)return false;
  int now_vertex = gt;
  while(prev[now_vertex] != INVALID){
    now_vertex = prev[now_vertex];
    if(now_vertex != gs && now_vertex != gt)I[now_vertex] = !I[now_vertex];
  }
  return true;
}

// Minimum weight matroid intersection solver
// Complexity: O(Cn^2 + n^4) (C : circuit query)
template <class Matroid1, class Matroid2, class T = int>
vector<bool> MatroidIntersection(Matroid1 matroid1,Matroid2 matroid2,vector<T> &weights){
  const int n = matroid1.size();
  assert(matroid2.size() == n);
  assert(weights.size() == n);
  
  vector<bool> I(n);
  while(matroid_intersection_augment(matroid1,matroid2,I,weights));
  return I;
}

int main(){
  
  ios_base::sync_with_stdio(0), cin.tie(0);
  while(1){
    int n,m,K;cin >> n >> m >> K;
    if(!n)break;
    ve parts(2);
    vector<int> R{K,n-K-1};
    vector<pair<int,int>> edge;
    vi weight;
    rep(i,m){
      int u,v,w;char l;cin >> u >> v >> w >> l;
      u--;v--;
      edge.emplace_back(u,v);
      parts[l-'A'].emplace_back(i);
      weight.emplace_back(w);
    }
    GraphicMatroid gm(n,edge);
    PartitionMatroid pm(m,parts,R);
    vb I = MatroidIntersection(gm,pm,weight);
    int cnt = accumulate(ALL(I),0);
    if(cnt != n-1)cout << "-1\n";
    else{
      int res = 0;
      rep(e,m)res += I[e]*weight[e];
      cout << res << "\n";
    }
  }
  

  return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 5000
final_rank: 12

code_snippet: #include <bits/stdc++.h>

#include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder {

// Implement (union by size) + (path compression)
// Reference:
// Zvi Galil and Giuseppe F. Italiano,
// Data structures and algorithms for disjoint set union problems
struct dsu {
  public:
    dsu() : _n(0) {}
    dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

}  // namespace atcoder

using namespace atcoder;
using namespace std;

using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vd = vector<double>;
using vvd = vector<vd>;
using vvvd = vector<vvd>;
#define all(A) A.begin(),A.end()
#define ALL(A) A.begin(),A.end()
#define rep(i, n) for (int i = 0; i < (int) (n); i++)
template<class T>
bool chmax(T& p, T q) {
    if (p < q) {
        p = q; return 1;
    }
    return 0;
};


void solve(ll N,ll M,ll K) {
    vector<vector<pair<ll,ll>>> GA(N),GB(N);
    rep(i,M){
        ll U,V,W;
        char C;
        cin>>U>>V>>W>>C;
        U--;V--;
        (C=='A'?GA:GB)[U].push_back({V,W});
        (C=='A'?GA:GB)[V].push_back({U,W});
    }
    {
        dsu dA(N),dB(N),d(N);
        ll nA=0,nB=0;
        rep(i,N){
            for(auto vw:GA[i]){
                if(!dA.same(i,vw.first))nA++;
                d.merge(i,vw.first);
                dA.merge(i,vw.first);
            }
            for(auto vw:GB[i]){
                if(!dB.same(i,vw.first))nB++;
                d.merge(i,vw.first);
                dB.merge(i,vw.first);
            }
        }
        if(d.size(0)!=N){
            cout<<-1<<endl;
            return;
        }
        if(nA<K){
            cout<<-1<<endl;
            return;
        }
        if(nB<N-K-1){
            cout<<-1<<endl;
            return;
        }
    }

    ll L=0,R=210;
    while(R-L>1){
        ll mid=(R+L)/2;


    vector<pair<ll,pair<ll,pair<ll,ll>>>> E;
        
        rep(i,N){
        for(auto &vw:GA[i]){
            vw.second+=(mid-105);
            E.push_back({vw.second,{0,{i,vw.first}}});
        }
        for(auto vw:GB[i]){
            E.push_back({vw.second,{1,{i,vw.first}}});
        }
    }
    sort(all(E));
    dsu d(N);
    ll cnt=0;
    rep(i,E.size()){
        ll v=E[i].second.second.first;
        ll u=E[i].second.second.second;
        if(d.same(u,v))continue;
        d.merge(u,v);
        cnt+=(E[i].second.first==0?1:0);
    }

        if(cnt>=K){
            L=mid;
        }
        else R=mid;
        
        rep(i,N){
            for(auto &vw:GA[i]){
                vw.second-=(mid-105);
            }
        }

    }

    ll an=0;
    // cout<<L<<endl;
    vector<pair<ll,pair<ll,pair<ll,ll>>>> E;
        
    rep(i,N){
        for(auto &vw:GA[i]){
            vw.second+=(L-105);
            E.push_back({vw.second,{0,{i,vw.first}}});
        }
        for(auto vw:GB[i]){
            E.push_back({vw.second,{1,{i,vw.first}}});
        }
    }
    sort(all(E));
    dsu d(N);
    ll cnt=0;
    rep(i,E.size()){
        ll v=E[i].second.second.first;
        ll u=E[i].second.second.second;
        if(d.same(u,v))continue;
        d.merge(u,v);
        cnt+=E[i].first;
    }
    cout<<cnt-(L-105)*K<<endl;
}

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


    ll N,M,K;
    while (cin >> N>>M>>K) {
        if (N == 0)return 0;
        solve(N,M,K);
    }

}
accuracy: 1
time_ms: 10
memory_kb: 3492
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;

bool is_end = false;

struct UnionFind
{
    int n;
    vector<int> par;
    
    UnionFind() = default;
    UnionFind(int _n) : n(_n), par(_n)
    {
        for (int i = 0; i < n; ++i) par[i] = i;
    }
    
    int root(int x)
    {
        if (par[x] == x) return x;
        else return par[x] = root(par[x]);
    }
    
    bool same(int x, int y)
    {
        return root(x) == root(y);
    }
    
    void merge(int x, int y)
    {
        par[root(y)] = root(x);
        return;
    }
    
};

void solve()
{
    int N, M, K; cin >> N >> M >> K;
    if (N == 0)
    {
        is_end = true;
        return;
    }
    
    vector<array<int, 3>> edgeA, edgeB;
    for (int i = 0; i < M; ++i)
    {
        int u, v, w; cin >> u >> v >> w;
        u--, v--;
        char c; cin >> c;
        
        if (c == 'A') edgeA.push_back({w, u, v});
        else edgeB.push_back({w, u, v});
    }
    sort(edgeA.begin(), edgeA.end());
    sort(edgeB.begin(), edgeB.end());
    
    int A = edgeA.size(), B = edgeB.size();
    vector<vector<tuple<int, int, int, UnionFind>>> connect(N+1, vector<tuple<int, int, int, UnionFind>>(N+1));
    
    const int INF = 1e9;
    connect[0][0] = {0, 0, 0, UnionFind(N)};
    for (int i = 0; i <= K; ++i)
    {
        for (int j = 0; j <= N - 1 - K; ++j)
        {
            if (i == 0 && j == 0) continue;
            
            int s = INF, a = A, b = B;
            UnionFind uf(N);
            
            // A
            if (i > 0)
            {
                auto [sa, ida, idb, ufa] = connect[i-1][j];
                bool done = false;
                for (int k = ida; k < A; ++k)
                {
                    auto [w, u, v] = edgeA[k];
                    if (ufa.same(u, v)) continue;
                    
                    ufa.merge(u, v);
                    sa += w;
                    ida = k + 1;
                    done = true;
                    break;
                }
                
                if (done)
                {
                    if (sa < s)
                    {
                        s = sa, a = ida, b = idb;
                        uf = ufa;
                    }
                }
            }
            
            // B
            if (j > 0)
            {
                auto [sb, ida, idb, ufb] = connect[i][j-1];
                bool done = false;
                for (int k = idb; k < B; ++k)
                {
                    auto [w, u, v] = edgeB[k];
                    if (ufb.same(u, v)) continue;
                    
                    ufb.merge(u, v);
                    sb += w;
                    idb = k + 1;
                    done = true;
                    break;
                }
                
                if (done)
                {
                    if (sb < s)
                    {
                        s = sb, a = ida, b = idb;
                        uf = ufb;
                    }
                }
            }
            
            connect[i][j] = {s, a, b, uf};
        }
    }
    
    {
        auto [s, a, b, uf] = connect[K][N - 1 - K];
        if (s >= INF) cout << -1 << endl;
        else cout << s << endl;
    }
    
    return;
}


int main()
{
    while (!is_end)
    {
        solve();
    }
    
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 13108
final_rank: 19

code_snippet: // #line 1 "library/Template/template.hpp"
#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define ALL(v) (v).begin(),(v).end()
#define UNIQUE(v) sort(ALL(v)),(v).erase(unique(ALL(v)),(v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v,x) int(lower_bound(ALL(v),(x))-(v).begin())
#define UB(v,x) int(upper_bound(ALL(v),(x))-(v).begin())

using ll=long long int;
using ull=unsigned long long;
using i128=__int128_t;
using u128=__uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template<typename T>inline bool chmax(T& a,T b){if(a<b){a=b;return 1;}return 0;}
template<typename T>inline bool chmin(T& a,T b){if(a>b){a=b;return 1;}return 0;}
template<typename T,typename U>T ceil(T x,U y){assert(y!=0); if(y<0)x=-x,y=-y; return (x>0?(x+y-1)/y:x/y);}
template<typename T,typename U>T floor(T x,U y){assert(y!=0); if(y<0)x=-x,y=-y; return (x>0?x/y:(x-y+1)/y);}
template<typename T>int popcnt(T x){return __builtin_popcountll(x);}
template<typename T>int topbit(T x){return (x==0?-1:63-__builtin_clzll(x));}
template<typename T>int lowbit(T x){return (x==0?-1:__builtin_ctzll(x));}
// #line 2 "library/Utility/fastio.hpp"
#include <unistd.h>

class FastIO {
    static constexpr int L = 1 << 16;
    char rdbuf[L];
    int rdLeft = 0, rdRight = 0;
    inline void reload() {
        int len = rdRight - rdLeft;
        memmove(rdbuf, rdbuf + rdLeft, len);
        rdLeft = 0, rdRight = len;
        rdRight += fread(rdbuf + len, 1, L - len, stdin);
    }
    inline bool skip() {
        for (;;) {
            while (rdLeft != rdRight and rdbuf[rdLeft] <= ' ')
                rdLeft++;
            if (rdLeft == rdRight) {
                reload();
                if (rdLeft == rdRight)
                    return false;
            } else
                break;
        }
        return true;
    }
    template <typename T, enable_if_t<is_integral<T>::value, int> = 0>
    inline bool _read(T &x) {
        if (!skip())
            return false;
        if (rdLeft + 20 >= rdRight)
            reload();
        bool neg = false;
        if (rdbuf[rdLeft] == '-') {
            neg = true;
            rdLeft++;
        }
        x = 0;
        while (rdbuf[rdLeft] >= '0' and rdLeft < rdRight) {
            x = x * 10 +
                (neg ? -(rdbuf[rdLeft++] ^ 48) : (rdbuf[rdLeft++] ^ 48));
        }
        return true;
    }
    inline bool _read(__int128_t &x) {
        if (!skip())
            return false;
        if (rdLeft + 40 >= rdRight)
            reload();
        bool neg = false;
        if (rdbuf[rdLeft] == '-') {
            neg = true;
            rdLeft++;
        }
        x = 0;
        while (rdbuf[rdLeft] >= '0' and rdLeft < rdRight) {
            x = x * 10 +
                (neg ? -(rdbuf[rdLeft++] ^ 48) : (rdbuf[rdLeft++] ^ 48));
        }
        return true;
    }
    inline bool _read(__uint128_t &x) {
        if (!skip())
            return false;
        if (rdLeft + 40 >= rdRight)
            reload();
        x = 0;
        while (rdbuf[rdLeft] >= '0' and rdLeft < rdRight) {
            x = x * 10 + (rdbuf[rdLeft++] ^ 48);
        }
        return true;
    }
    template <typename T, enable_if_t<is_floating_point<T>::value, int> = 0>
    inline bool _read(T &x) {
        if (!skip())
            return false;
        if (rdLeft + 20 >= rdRight)
            reload();
        bool neg = false;
        if (rdbuf[rdLeft] == '-') {
            neg = true;
            rdLeft++;
        }
        x = 0;
        while (rdbuf[rdLeft] >= '0' and rdbuf[rdLeft] <= '9' and
               rdLeft < rdRight) {
            x = x * 10 + (rdbuf[rdLeft++] ^ 48);
        }
        if (rdbuf[rdLeft] != '.')
            return true;
        rdLeft++;
        T base = .1;
        while (rdbuf[rdLeft] >= '0' and rdbuf[rdLeft] <= '9' and
               rdLeft < rdRight) {
            x += base * (rdbuf[rdLeft++] ^ 48);
            base *= .1;
        }
        if (neg)
            x = -x;
        return true;
    }
    inline bool _read(char &x) {
        if (!skip())
            return false;
        if (rdLeft + 1 >= rdRight)
            reload();
        x = rdbuf[rdLeft++];
        return true;
    }
    inline bool _read(string &x) {
        if (!skip())
            return false;
        for (;;) {
            int pos = rdLeft;
            while (pos < rdRight and rdbuf[pos] > ' ')
                pos++;
            x.append(rdbuf + rdLeft, pos - rdLeft);
            if (rdLeft == pos)
                break;
            rdLeft = pos;
            if (rdLeft == rdRight)
                reload();
            else
                break;
        }
        return true;
    }
    template <typename T> inline bool _read(vector<T> &v) {
        for (auto &x : v) {
            if (!_read(x))
                return false;
        }
        return true;
    }

    char wtbuf[L], tmp[50];
    int wtRight = 0;
    inline void _write(const char &x) {
        if (wtRight > L - 32)
            flush();
        wtbuf[wtRight++] = x;
    }
    inline void _write(const string &x) {
        for (auto &c : x)
            _write(c);
    }
    template <typename T, enable_if_t<is_integral<T>::value, int> = 0>
    inline void _write(T x) {
        if (wtRight > L - 32)
            flush();
        if (x == 0) {
            _write('0');
            return;
        } else if (x < 0) {
            _write('-');
            if (__builtin_expect(x == std::numeric_limits<T>::min(), 0)) {
                switch (sizeof(x)) {
                case 2:
                    _write("32768");
                    return;
                case 4:
                    _write("2147483648");
                    return;
                case 8:
                    _write("9223372036854775808");
                    return;
                }
            }
            x = -x;
        }
        int pos = 0;
        while (x != 0) {
            tmp[pos++] = char((x % 10) | 48);
            x /= 10;
        }
        rep(i, 0, pos) wtbuf[wtRight + i] = tmp[pos - 1 - i];
        wtRight += pos;
    }
    inline void _write(__int128_t x) {
        if (wtRight > L - 40)
            flush();
        if (x == 0) {
            _write('0');
            return;
        } else if (x < 0) {
            _write('-');
            x = -x;
        }
        int pos = 0;
        while (x != 0) {
            tmp[pos++] = char((x % 10) | 48);
            x /= 10;
        }
        rep(i, 0, pos) wtbuf[wtRight + i] = tmp[pos - 1 - i];
        wtRight += pos;
    }
    inline void _write(__uint128_t x) {
        if (wtRight > L - 40)
            flush();
        if (x == 0) {
            _write('0');
            return;
        }
        int pos = 0;
        while (x != 0) {
            tmp[pos++] = char((x % 10) | 48);
            x /= 10;
        }
        rep(i, 0, pos) wtbuf[wtRight + i] = tmp[pos - 1 - i];
        wtRight += pos;
    }
    inline void _write(double x) {
        ostringstream oss;
        oss << fixed << setprecision(15) << double(x);
        string s = oss.str();
        _write(s);
    }
    template <typename T> inline void _write(const vector<T> &v) {
        rep(i, 0, v.size()) {
            if (i)
                _write(' ');
            _write(v[i]);
        }
    }

  public:
    FastIO() {}
    ~FastIO() { flush(); }
    inline void read() {}
    template <typename Head, typename... Tail>
    inline void read(Head &head, Tail &...tail) {
        assert(_read(head));
        read(tail...);
    }
    template <bool ln = true, bool space = false> inline void write() {
        if (ln)
            _write('\n');
    }
    template <bool ln = true, bool space = false, typename Head,
              typename... Tail>
    inline void write(const Head &head, const Tail &...tail) {
        if (space)
            _write(' ');
        _write(head);
        write<ln, true>(tail...);
    }
    inline void flush() {
        fwrite(wtbuf, 1, wtRight, stdout);
        wtRight = 0;
    }
};

#define debug(var)  do{std::cerr << #var << " : ";view(var); cerr << '\n';}while(0)
template<typename T> void view(T e){std::cerr << e;}
template<typename T,typename U> void view(pair<T,U> e){
    std::cerr << '{';
    view(e.first);
    std::cerr << ',';
    view(e.second);
    std::cerr << '}';
}
template <typename T, template<class> class C> void view(const C<T>& v){
    std::cerr << "[";
    for(const auto& e : v){ view(e); cerr << ','; }
    std::cerr << "]";
}


/**
 * @brief Fast IO
 */
// #line 3 "sol.cpp"

struct GraphicMatroid{
    using P=pair<int,int>;
    int n;
    vector<P> E;
    vector<vector<P>> G;
    vector<int> allow;
    GraphicMatroid(){}
    GraphicMatroid(int n,vector<P>& E):n(n),E(E),G(n){
        rep(i,0,SZ(E)){
            auto [u,v]=E[i];
            G[u].push_back({v,i});
            G[v].push_back({u,i});
        }
    }
    void set(vector<int>& I){
        allow=I;
    }
    vector<int> circuit(int e){
        auto [x,y]=E[e];
        vector<int> ret;
        ret.push_back(e);
        auto dfs=[&](auto& dfs,int v,int p)->bool{
            if(v==y)return true;
            for(auto& [to,i]:G[v])if(allow[i] and to!=p){
                ret.push_back(i);
                if(dfs(dfs,to,v))return true;
                ret.pop_back();
            }
            return false;
        };
        if(dfs(dfs,x,-1))return ret;
        else return {};
    }
};

struct PartitionMatroid{
    vector<int> grp; // -1:not assign
    vector<int> lim;
    vector<vector<int>> cnt;
    PartitionMatroid(){}
    PartitionMatroid(vector<int>& grp,vector<int> lim):grp(grp),lim(lim){}
    void set(vector<int>& I){
        cnt.assign(SZ(lim),{});
        rep(i,0,SZ(grp))if(I[i]!=0 and grp[i]!=-1){
            cnt[grp[i]].push_back(i);
        }
    }
    vector<int> circuit(int e){
        if(grp[e]==-1)return {};
        if(SZ(cnt[grp[e]])+1>lim[grp[e]]){
            vector<int> ret=cnt[grp[e]];
            ret.push_back(e);
            return ret;
        }
        else return {};
    }
};

template<typename M1,typename M2,typename Val>
pair<vector<Val>,vector<vector<int>>> MinimumMatroidIntersection(M1& m1,M2& m2,vector<Val>& ws){
    using P=pair<Val,int>;
    int n=SZ(ws);
    
    vector<Val> ret1;
    vector<vector<int>> ret2;
    
    Val profit=0;
    vector<int> I(n);
    ret1.push_back(profit);
    ret2.push_back(I);
    
    for(;;){
        vector G(n+2,vector<P>());
        int S=n,T=n+1;
        m1.set(I);
        m2.set(I);
        
        rep(e,0,n){
            if(I[e])continue;
            auto c1=m1.circuit(e);
            if(c1.empty())G[S].push_back({ws[e]*(n+1)+1,e});
            else for(auto& to:c1)if(e!=to){
                G[to].push_back({ws[e]*(n+1)+1,e});
            }
            auto c2=m2.circuit(e);
            if(c2.empty())G[e].push_back({Val(0),T});
            else for(auto& to:c2)if(e!=to){
                G[e].push_back({-ws[to]*(n+1)+1,to});
            }
        }
        
        vector<ll> dist(n+2,INF);
        dist[S]=0;
        vector<int> pre(n+2,-1);
        for(;;){
            bool upd=0;
            rep(v,0,n+2)for(auto& [cost,to]:G[v]){
                if(chmin(dist[to],dist[v]+cost)){
                    pre[to]=v;
                    upd=1;
                }
            }
            if(!upd)break;
        }
        
        if(dist[T]==INF)break;
        int cur=T;
        while(cur!=S){
            cur=pre[cur];
            if(cur!=S){
                I[cur]^=1;
                if(I[cur])profit+=ws[cur];
                else profit-=ws[cur];
            }
        }
        ret1.push_back(profit);
        ret2.push_back(I);
        
        // debug(profit);
        // debug(I);
    }
    return {ret1,ret2};
}


FastIO io;
int main(){
    for(;;){
        int n,m,k;
        io.read(n,m,k);
        if(n==0)break;
        using P=pair<int,int>;
        vector<P> E;
        vector<ll> ws(m);
        vector<int> grp(m),lim={k,n-1-k};
        rep(i,0,m){
            int u,v,w;
            char c;
            io.read(u,v,w,c);
            u--; v--;
            E.push_back({u,v});
            ws[i]=w;
            if(c=='A')grp[i]=0;
            else grp[i]=1;
        }
        
        GraphicMatroid m1(n,E);
        PartitionMatroid m2(grp,lim);
        
        auto [ret,tmp]=MinimumMatroidIntersection(m1,m2,ws);
        if(SZ(ret)==n)io.write(ret.back());
        else io.write(-1);
    }
    return 0;
}
accuracy: 1
time_ms: 810
memory_kb: 4904
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, n) for (int i = 0; i < (n); i++)
#define per(i, n) for (int i = (n)-1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define per2(i, l, r) for (int i = (r)-1; i >= (l); i--)
#define each(e, x) for (auto &e : x)
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define pb push_back
#define eb emplace_back
#define MM << ' ' <<
#define TT template <typename T>
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

const int inf = (1 << 30) - 1;

TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

int main() {
    while (true) {
        int N, M, K;
        cin >> N >> M >> K;

        if (N == 0) break;

        vector<int> r(N, -1);

        auto root = [&](auto &&root, int v) -> int {
            if (r[v] == -1) return v;
            return r[v] = root(root, r[v]);
        };

        auto unite = [&](int u, int v) {
            u = root(root, u), v = root(root, v);
            if (u == v) return false;
            r[v] = u;
            return true;
        };

        vector<tuple<int, int, int, char>> es;

        rep(i, M) {
            int u, v, w;
            char c;
            cin >> u >> v >> w >> c;
            u--, v--;
            es.eb(w, u, v, c);
        }

        sort(all(es));

        int l1 = 0, l2 = 0;
        int ans = 0;

        vector<bool> used(M, false);

        rep(i, M) {
            auto [w, u, v, c] = es[i];
            if (unite(u, v)) {
                ans += w;
                if (c == 'A') l1++;
                if (c == 'B') l2++;
                used[i] = true;
            }
        }

        // cout << l1 MM l2 << endl;

        if (l1 + l2 != N - 1) {
            cout << "-1\n";
            continue;
        }

        // cout << N MM M MM K << endl;

        while (l1 != K) {
            vector<vector<tuple<int, int, int, int>>> li(N);
            rep(i, M) {
                if (!used[i]) continue;
                auto [w, u, v, c] = es[i];
                li[u].eb(v, c, w, i);
                li[v].eb(u, c, w, i);
            }

            vector<int> d(N, inf);
            vector<tuple<int, int, int, int>> pre(N);
            queue<int> que;
            que.emplace(0);
            d[0] = 0;
            while (!empty(que)) {
                int i = que.front();
                que.pop();
                for (auto [j, c, w, id] : li[i]) {
                    if (chmin(d[j], d[i] + 1)) {
                        pre[j] = make_tuple(i, c, w, id);
                        que.emplace(j);
                    }
                }
            }

            char x = (l1 < K ? 'A' : 'B');
            int mi = inf;
            pii P{-1, -1};

            rep(i, M) {
                auto [w, u, v, c] = es[i];
                if (used[i] || c != x) continue;
                int ma = -inf, ma_id = -1;
                while (u != v) {
                    if (d[u] < d[v]) swap(u, v);
                    auto [p, c, w, id] = pre[u];
                    if (c != x && chmax(ma, w)) {
                        ma_id = id; //
                    }
                    u = p;
                }
                if (chmin(mi, w - ma)) {
                    P = {i, ma_id}; //
                }
            }

            if (mi == inf) {
                ans = -1;
                break;
            }

            ans += mi;
            used[P.first] = true;
            used[P.second] = false;
            if (l1 < K) l1++;
            if (l1 > K) l1--;
        }

        cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 30
memory_kb: 3396
final_rank: 4

code_snippet: #include<iostream>
#include<vector>
#include<algorithm>
#include<cassert>
using namespace std;
struct UF{
	vector<int>pr;
	UF(int n):pr(n,-1){}
	int find(int u)
	{
		if(pr[u]>=0)return pr[u]=find(pr[u]);
		return u;
	}
	bool merge(int u,int v)
	{
		u=find(u);
		v=find(v);
		if(u==v)return false;
		if(-pr[u]<-pr[v])swap(u,v);
		pr[u]+=pr[v];
		pr[v]=u;
		return true;
	}
};
struct edge{
	int u,v,w;
	bool operator<(const edge&rhs)const{return w<rhs.w;}
};
ostream&operator<<(ostream&os,const edge&e)
{
	return os<<"("<<e.u+1<<", "<<e.v+1<<", "<<e.w<<")";
}
int N,M,K;
vector<edge>A,B;
vector<edge>f(vector<edge>E)
{
	UF uf(N);
	vector<edge>ret;
	sort(E.begin(),E.end());
	for(edge e:E)
	{
		if(uf.merge(e.u,e.v))ret.push_back(e);
	}
	return ret;
}
int main()
{
	while(cin>>N>>M>>K,N)
	{
		A.clear();
		B.clear();
		for(int i=0;i<M;i++)
		{
			edge E;
			cin>>E.u>>E.v>>E.w;
			E.u--,E.v--;
			char l;
			cin>>l;
			if(l=='A')A.push_back(E);
			else B.push_back(E);
		}
		A=f(A);
		B=f(B);
		vector<edge>useA,restA;
		{
			UF uf(N);
			for(edge e:B)uf.merge(e.u,e.v);
			for(edge e:A)
			{
				if(uf.merge(e.u,e.v))
				{
					useA.push_back(e);
				}
				else restA.push_back(e);
			}
		}
		int cnt=K-(int)useA.size();
		if(cnt<0||cnt>restA.size())
		{
			cout<<-1<<endl;
			continue;
		}
		for(int t=0;t<cnt;t++)
		{
			UF uf(N);
			for(edge e:useA)assert(uf.merge(e.u,e.v));
			/*
			int ALL=0;
			UF ALLuf=uf;
			for(edge e:B)if(ALLuf.merge(e.u,e.v))ALL+=e.w;
			*/
			int MN=1e9,MNi;
			for(int i=0;i<restA.size();i++)
			{
				UF NOWuf=uf;
				assert(NOWuf.merge(restA[i].u,restA[i].v));
				int now=restA[i].w;
				for(edge e:B)if(NOWuf.merge(e.u,e.v))now+=e.w;
				if(MN>now)
				{
					MN=now;
					MNi=i;
				}
			}
			useA.push_back(restA[MNi]);
			restA.erase(restA.begin()+MNi);
		}
		assert(useA.size()==K);
		UF uf(N);
		for(edge e:useA)assert(uf.merge(e.u,e.v));
		for(edge e:B)if(uf.merge(e.u,e.v))
		{
			useA.push_back(e);
			//cout<<e<<" from B\n";
		}
		if(useA.size()<N-1)
		{
			cout<<-1<<endl;
			continue;
		}
		assert(useA.size()==N-1);
		int ans=0;
		for(edge e:useA)ans+=e.w;
		cout<<ans<<endl;
	}
}
accuracy: 1
time_ms: 60
memory_kb: 3484
final_rank: 7

code_snippet: #include <bits/stdc++.h>

namespace luz {

  using usize = std::size_t;
  using isize = std::ptrdiff_t;

  struct rep {
    struct itr {
      usize i;
      constexpr itr(const usize i) noexcept: i(i) {}
      void operator++() noexcept {
        ++i;
      }
      constexpr usize operator*() const noexcept {
        return i;
      }
      constexpr bool operator!=(
          const itr x) const noexcept {
        return i != x.i;
      }
    };
    const itr f, l;
    constexpr rep(const usize f, const usize l) noexcept
      : f(std::min(f, l)),
      l(l) {}
    constexpr auto begin() const noexcept {
      return f;
    }
    constexpr auto end() const noexcept {
      return l;
    }
  };

}

namespace luz {
  class DisjointSetUnion {
    usize n_;

    std::vector< isize > vals_;

    void bound_check(usize v) const {
      assert(v < n_);
    }

    usize impl_leader(usize v) {
      if (vals_[v] < 0) return v;
      return vals_[v] = leader(vals_[v]);
    }

   public:
    DisjointSetUnion() = default;
    explicit DisjointSetUnion(usize n) : n_(n), vals_(n, -1) {}

    usize size() const {
      return n_;
    }

    usize leader(usize v) {
      bound_check(v);
      return impl_leader(v);
    }

    bool same(usize u, usize v) {
      bound_check(u), bound_check(v);
      return impl_leader(u) == impl_leader(v);
    }

    usize merge(usize u, usize v) {
      bound_check(u);
      bound_check(v);

      isize x = impl_leader(u);
      isize y = impl_leader(v);
      if (x == y) return x;
      if (-vals_[x] < -vals_[y]) std::swap(x, y);
      vals_[x] += vals_[y];
      vals_[y] = x;
      return x;
    }

    usize group_size(usize v) {
      bound_check(v);
      return -vals_[impl_leader(v)];
    }
  };

}

void solve(int n, int m, int k) {
  struct plan {
    int u, v, w, is_a;
  };

  luz::DisjointSetUnion dsu(n);
  std::vector< plan > plans(m);
  for (auto &p: plans) {
    char c;
    std::cin >> p.u >> p.v >> p.w >> c;
    p.is_a = (c == 'A');
    p.u--;
    p.v--;

    dsu.merge(p.u, p.v);
  }

  if (dsu.group_size(0) != n) {
    std::cout << -1 << std::endl;
    return;
  }

  // dw \in [-100, 100]
  auto calc = [&](int dw) {
    for (auto &p: plans) {
      if (not p.is_a) continue;
      p.w += dw;
    }

    auto aplans = plans;
    auto bplans = plans;

    for (auto &p: plans) {
      if (not p.is_a) continue;
      p.w -= dw;
    }

    auto cmp_a = [&](const plan &a, const plan &b) {
      if (a.w == b.w) {
        return a.is_a < b.is_a;
      }
      return a.w < b.w;
    };
    auto cmp_b = [&](const plan &a, const plan &b) {
      if (a.w == b.w) {
        return a.is_a > b.is_a;
      }
      return a.w < b.w;
    };

    std::sort(aplans.begin(), aplans.end(), cmp_a);
    std::sort(bplans.begin(), bplans.end(), cmp_b);

    luz::DisjointSetUnion af(n), bf(n);
    int cnt_a = 0, cnt_b = 0;
    int mst_a = 0, mst_b = 0;
    
    for (auto &p: aplans) {
      int u = p.u;
      int v = p.v;
      if (af.same(u, v)) continue;
      if (p.is_a) cnt_a++;
      af.merge(u, v);
      mst_a += p.w;
    }
    for (auto &p: bplans) {
      int u = p.u;
      int v = p.v;
      if (bf.same(u, v)) continue;
      if (p.is_a) cnt_b++;
      bf.merge(u, v);
      mst_b += p.w;
    }

    assert(mst_a == mst_b);

    return std::make_tuple(cnt_a, cnt_b, mst_a);
  };

  int ok = 100, ng = -101;
  while (ok - ng > 1) {
    // std::cerr << "(" << ng << ", " << ok << "]" << std::endl;
    int dw = (ok + ng) / 2;

    // A 側に下駄をはかせて A を使える下界、上界
    auto [lb, up, mst] = calc(dw);
    // std::cerr << lb << " " << up << " " << mst << std::endl;

    if (k < lb) {
      ng = dw;
    } else {
      ok = dw;
    }
  }

  auto [lb, up, mst] = calc(ok);
  // std::cerr << ok << std::endl;
  // std::cerr << lb << " " << up << " " << mst << std::endl;

  if (lb <= k and k <= up) {
    std::cout << mst - k * ok << std::endl;
  } else {
    std::cout << -1 << std::endl;
  }
}

int main() {
  int n, m, k;
  while (std::cin >> n >> m >> k, n) {
    solve(n, m, k);
  }
}
accuracy: 1
time_ms: 10
memory_kb: 3432
final_rank: 2

code_snippet: #include <bits/stdc++.h>

namespace luz {

  using usize = std::size_t;
  using isize = std::ptrdiff_t;

  struct rep {
    struct itr {
      usize i;
      constexpr itr(const usize i) noexcept: i(i) {}
      void operator++() noexcept {
        ++i;
      }
      constexpr usize operator*() const noexcept {
        return i;
      }
      constexpr bool operator!=(
          const itr x) const noexcept {
        return i != x.i;
      }
    };
    const itr f, l;
    constexpr rep(const usize f, const usize l) noexcept
      : f(std::min(f, l)),
      l(l) {}
    constexpr auto begin() const noexcept {
      return f;
    }
    constexpr auto end() const noexcept {
      return l;
    }
  };

}

namespace luz {
  class DisjointSetUnion {
    usize n_;

    std::vector< isize > vals_;

    void bound_check(usize v) const {
      assert(v < n_);
    }

    usize impl_leader(usize v) {
      if (vals_[v] < 0) return v;
      return vals_[v] = leader(vals_[v]);
    }

   public:
    DisjointSetUnion() = default;
    explicit DisjointSetUnion(usize n) : n_(n), vals_(n, -1) {}

    usize size() const {
      return n_;
    }

    usize leader(usize v) {
      bound_check(v);
      return impl_leader(v);
    }

    bool same(usize u, usize v) {
      bound_check(u), bound_check(v);
      return impl_leader(u) == impl_leader(v);
    }

    usize merge(usize u, usize v) {
      bound_check(u);
      bound_check(v);

      isize x = impl_leader(u);
      isize y = impl_leader(v);
      if (x == y) return x;
      if (-vals_[x] < -vals_[y]) std::swap(x, y);
      vals_[x] += vals_[y];
      vals_[y] = x;
      return x;
    }

    usize group_size(usize v) {
      bound_check(v);
      return -vals_[impl_leader(v)];
    }
  };

}

void solve(int n, int m, int k) {
  struct plan {
    int u, v, w, is_a;
  };

  luz::DisjointSetUnion dsu(n);
  std::vector< plan > plans(m);
  for (auto &p: plans) {
    char c;
    std::cin >> p.u >> p.v >> p.w >> c;
    p.is_a = (c == 'A');
    p.u--;
    p.v--;

    dsu.merge(p.u, p.v);
  }

  if (dsu.group_size(0) != n) {
    std::cout << -1 << std::endl;
    return;
  }

  // dw \in [-100, 100]
  auto calc = [&](int dw) {
    for (auto &p: plans) {
      if (not p.is_a) continue;
      p.w += dw;
    }

    auto aplans = plans;
    auto bplans = plans;

    for (auto &p: plans) {
      if (not p.is_a) continue;
      p.w -= dw;
    }

    auto cmp_a = [&](const plan &a, const plan &b) {
      if (a.w == b.w) {
        return a.is_a < b.is_a;
      }
      return a.w < b.w;
    };
    auto cmp_b = [&](const plan &a, const plan &b) {
      if (a.w == b.w) {
        return a.is_a > b.is_a;
      }
      return a.w < b.w;
    };

    std::sort(aplans.begin(), aplans.end(), cmp_a);
    std::sort(bplans.begin(), bplans.end(), cmp_b);

    luz::DisjointSetUnion af(n), bf(n);
    int cnt_a = 0, cnt_b = 0;
    int mst_a = 0, mst_b = 0;
    
    for (auto &p: aplans) {
      int u = p.u;
      int v = p.v;
      if (af.same(u, v)) continue;
      if (p.is_a) cnt_a++;
      af.merge(u, v);
      mst_a += p.w;
    }
    for (auto &p: bplans) {
      int u = p.u;
      int v = p.v;
      if (bf.same(u, v)) continue;
      if (p.is_a) cnt_b++;
      bf.merge(u, v);
      mst_b += p.w;
    }

    assert(mst_a == mst_b);

    return std::make_tuple(cnt_a, cnt_b, mst_a);
  };

  int ok = 100, ng = -101;
  while (ok - ng > 1) {
    // std::cerr << "(" << ng << ", " << ok << "]" << std::endl;
    int dw = (ok + ng) / 2;

    // A 側に下駄をはかせて A を使える下界、上界
    auto [lb, up, mst] = calc(dw);
    // std::cerr << lb << " " << up << " " << mst << std::endl;

    if (k < lb) {
      ng = dw;
    } else {
      ok = dw;
    }
  }

  auto [lb, up, mst] = calc(ok);
  // std::cerr << ok << std::endl;
  // std::cerr << lb << " " << up << " " << mst << std::endl;

  if (lb <= k and k <= up) {
    std::cout << mst - k * ok << std::endl;
  } else {
    std::cout << -1 << std::endl;
  }
}

int main() {
  int n, m, k;
  while (std::cin >> n >> m >> k, n) {
    solve(n, m, k);
  }
}
accuracy: 1
time_ms: 10
memory_kb: 3420
final_rank: 1

code_snippet: #include <bits/stdc++.h>

#define rep(i, s, n) for (int i = (int)s; i < (int)n; i++)
#define rrep(i, s, n) for (int i = (int)(n)-1; i >= s; i--)
#define all(v) v.begin(), v.end()

using ll = long long;

struct dsu {
    std::vector<int> par;

   public:
    dsu(int n = 0) : par(n, -1) {}

    int leader(int x) {
        if (par[x] < 0)
            return x;
        else
            return par[x] = leader(par[x]);
    }

    bool same(int x, int y) { return leader(x) == leader(y); }

    bool merge(int x, int y) {
        x = leader(x);
        y = leader(y);
        if(x == y) return false;
        if (par[x] > par[y]) std::swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int size(int x) {
        x = leader(x);
        return -par[x];
    }
};

int main() {
    int n, m, k;
    while (std::cin >> n >> m >> k, !(n == 0 && m == 0 && k == 0)) {
        std::vector edges(m, std::vector<int>(4));
        rep(i, 0, m) {
            std::cin >> edges[i][0] >> edges[i][1];
            edges[i][0]--;
            edges[i][1]--;
            std::cin >> edges[i][2];
            char c;
            std::cin >> c;
            edges[i][3] = c - 'A';
        }
        auto check = [&](std::vector<std::vector<int>> a, std::vector<std::vector<int>> b, int cnt) -> bool {
            dsu uf(n);
            for(auto edge: b) {
                uf.merge(edge[0], edge[1]);
            }
            int t = 0;
            for(auto edge: a) {
                int u = edge[0];
                int v = edge[1];
                if(!uf.same(u, v)) {
                    t++;
                    uf.merge(u, v);
                }
            }
            return t <= cnt && uf.size(0) == n;
        };
        {
            std::vector<std::vector<int>> edges_a, edges_b;
            for(auto edge: edges) {
                if(edge[3] == 0) edges_a.emplace_back(edge);
                else edges_b.emplace_back(edge);
            }
            if(!(check(edges_a, edges_b, k) && check(edges_b, edges_a, n-1-k))) {
                std::cout << "-1\n";
                continue;
            }
        }
        ll ok = -200, ng = 200;
        auto f = [&](ll c) -> std::pair<ll, int> {
            std::vector ps(m, std::vector<int>(4));
            rep(i, 0, m) {
                ps[i] = edges[i];
                if (ps[i][3] == 0) ps[i][2] += c;
            }
            std::sort(all(ps), [](auto lhs, auto rhs) {
                return (lhs[2] != rhs[2]) ? lhs[2] < rhs[2] : lhs[3] < rhs[3];
            });
            dsu uf(n);
            int cnt = 0;
            ll sum = 0;
            for (auto edge : ps) {
                int u = edge[0];
                int v = edge[1];
                int w = edge[2];
                if (uf.same(u, v)) continue;
                uf.merge(u, v);
                sum += w;
                if (edge[3] == 0) cnt++;
            }
            return {sum, cnt};
        };
        while (std::abs(ok - ng) > 1) {
            ll mid = (ok + ng) / 2;
            auto [sum, cnt] = f(mid);
            if (cnt >= k) {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        auto [sum, cnt] = f(ok);
        sum -= k * ok;
        std::cout << sum << '\n';
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3544
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,s,t) for (int i = (int)(s); i < (int)(t); ++i)
#define all(x) (x).begin(), (x).end()

struct UnionFind {
    vector<int> data;

    UnionFind(int n) : data(n, -1) {}

    int find(int x) {
        if (data[x] < 0) return x;
        return data[x] = find(data[x]);
    }

    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        if (data[x] > data[y]) swap(x, y);
        data[x] += data[y];
        data[y] = x;
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }
};

template <typename T>
void print(set<T>& st) {
    for (auto& i : st) cout << i << " ";
    cout << endl;
}

template <typename T, typename U>
void print(pair<T, U>& p) {
    cout << "(" << p.first << "," << p.second << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    while (true) {
        int n, m, k;
        cin >> n >> m >> k;
        if (n == 0) break;
        vector<tuple<int, int, int, char>> edges(m);
        set<int> unused, used;
        vector<pair<int, int>> init(m);
        rep(i,0,m) {
            int u, v, w;
            char l;
            cin >> u >> v >> w >> l;
            --u, --v;
            edges[i] = {u, v, w, l};
            init[i] = {w, i};
        }
        sort(all(init));

        UnionFind uf(n);
        int cnt = 0;
        for (auto [_, i] : init) {
            auto [u, v, w, l] = edges[i];
            if (l == 'A' && cnt < k && !uf.same(u, v)) {
                uf.unite(u, v);
                used.insert(i);
                ++cnt;
            } else {
                unused.insert(i);
            }
        }

        if (cnt < k) {
            cout << -1 << "\n";
            continue;
        }

        auto flip = [&](int i) {
            if (used.count(i)) {
                used.erase(i);
                unused.insert(i);
            } else {
                unused.erase(i);
                used.insert(i);
            }
        };

        // print(used);

        bool ok = true;
        rep(_,0,n-k-1) {
            // print(used);
            UnionFind uf(n);
            vector<vector<pair<int, int>>> G(n);
            for (int i : used) {
                auto [u, v, w, l] = edges[i];
                uf.unite(u, v);
                G[u].push_back({v, i});
                G[v].push_back({u, i});
            }

            // find min source
            pair<int, int> minA(1e9, -1), minB(1e9, -1);
            for (int i : unused) {
                auto [u, v, w, l] = edges[i];
                if (!uf.same(u, v)) {
                    if (l == 'A') minA = min(minA, {w, i});
                    else minB = min(minB, {w, i});
                }
            }

            // find min AB pair
            vector<int> par(n, -1), pare(n, -1), dep(n, -1);

            auto dfs = [&](auto& dfs, int v) -> void {
                for (auto [c, i] : G[v]) {
                    if (c == par[v]) continue;
                    dep[c] = dep[v] + 1;
                    par[c] = v;
                    pare[c] = i;
                    dfs(dfs, c);
                }
            };

            rep(i,0,n) {
                if (dep[i] != -1) continue;
                dep[i] = 0;
                dfs(dfs, i);
            }

            tuple<int, int, int> minAB(1e9, -1, -1);
            for (int i : unused) {
                auto [u, v, w, l] = edges[i];
                if (l == 'A' || !uf.same(u, v)) continue;
                pair<int, int> maxA(-1e9, -1);
                while (u != v) {
                    // cout << u << " " << v << endl;
                    if (dep[u] < dep[v]) swap(u, v);
                    int e = pare[u];
                    if (get<3>(edges[e]) == 'A') maxA = max(maxA, {get<2>(edges[e]), e});
                    u = par[u];
                }
                auto [x, j] = maxA;
                if (j == -1) continue;
                minAB = min(minAB, {w-x, i, j});
            }

            // print(minA);
            // print(minB);

            if (minB.first <= get<0>(minAB)+minA.first) {
                auto [w, i] = minB;
                if (i == -1) {
                    ok = false;
                    break;
                }
                flip(i);
            } else {
                auto [w, i, j] = minAB;
                auto [x, k] = minA;
                if (i == -1 || j == -1 || k == -1) {
                    ok = false;
                    break;
                }
                flip(i);
                flip(j);
                flip(k);
            }
        }
        // print(used);
        if (ok) {
            ll ans = 0;
            for (int i : used) {
                ans += get<2>(edges[i]);
            }
            cout << ans << "\n";
        } else {
            cout << -1 << "\n";
        }
    }
}
accuracy: 1
time_ms: 40
memory_kb: 3536
final_rank: 6

code_snippet: #include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <utility>
#include <vector>

namespace luz {

  using isize = std::ptrdiff_t;
  using usize = std::size_t;

  using i32 = std::int32_t;
  using i64 = std::int64_t;
  using u32 = std::uint32_t;
  using u64 = std::uint64_t;
  
} // namespace luz

namespace luz {

  struct rep {
    struct itr {
      usize i;
      constexpr itr(const usize i) noexcept : i(i) {}
      void operator++() noexcept { ++i; }
      constexpr usize operator*() const noexcept { return i; }
      constexpr bool operator!=(const itr x) const noexcept { return i != x.i; }
    };
    const itr f, l;
    constexpr rep(const usize f, const usize l) noexcept
      : f(std::min(f, l)), l(l) {}
    constexpr auto begin() const noexcept { return f; }
    constexpr auto end() const noexcept { return l; }
  };

  struct rrep {
    struct itr {
      usize i;
      constexpr itr(const usize i) noexcept : i(i) {}
      void operator++() noexcept { --i; }
      constexpr usize operator*() const noexcept { return i; }
      constexpr bool operator!=(const itr x) const noexcept { return i != x.i; }
    };
    const itr f, l;
    constexpr rrep(const usize f, const usize l) noexcept
      : f(l - 1), l(std::min(f, l) - 1) {}
    constexpr auto begin() const noexcept { return f; }
    constexpr auto end() const noexcept { return l; }
  };

} // namespace luz

namespace luz {

  void set_fast_ios() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
  }

} // namespace luz

namespace luz {

  void io_set(usize precision) {
    std::cout << std::fixed << std::setprecision(precision);
    std::cerr << std::fixed << std::setprecision(precision);
  }

} // namespace luz

namespace luz {

  template< typename T = i64 > T input() {
    T tmp;
    std::cin >> tmp;
    return tmp;
  }

} // namespace luz

namespace luz {

  template< typename T >
  std::ostream &operator<<(std::ostream &os, std::vector< T > &vs) {
    for (usize i: rep(0, vs.size())) {
      os << vs[i] << (i + 1 != vs.size() ? " " : "");
    }
    return os;
  }

  template< typename T >
  std::istream &operator>>(std::istream &is, std::vector< T > &vs) {
    for (T &v: vs) {
      is >> v;
    }
    return is;
  }

} // namespace luz

namespace luz {

  template< typename T1, typename T2 >
  std::ostream &operator<<(std::ostream &os, std::pair < T1, T2 > &p) {
    os << "(" << p.first << ", " << p.second << ")";
    return os;
  }

  template< typename T1, typename T2 >
  std::istream &operator>>(std::istream &is, std::pair< T1, T2 > &p) {
    is >> p.first >> p.second;
    return is;
  }

} // namespace luz

namespace luz {

  template <typename T>
  std::vector<T> make_vector(usize a, T b) {
    return std::vector<T>(a, b);
  }

  template <typename... Ts>
  auto make_vector(usize a, Ts... ts) {
    return std::vector<decltype(make_vector(ts...))>(a, make_vector(ts...));
  }

} // namespace luz

namespace luz {

  template <typename T1, typename T2>
  inline bool chmax(T1 &a, T2 b) {
    return a < b and (a = b, true);
  }

  template <typename T1, typename T2>
  inline bool chmin(T1 &a, T2 b) {
    return a > b and (a = b, true);
  }

} // namespace luz

#include <map>

struct UnionFind {
  std::vector< int > data;

  UnionFind() = default;

  explicit UnionFind(size_t sz) : data(sz, -1) {}

  bool unite(int x, int y) {
    x = find(x), y = find(y);
    if(x == y) return false;
    if(data[x] > data[y]) std::swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return true;
  }

  int find(int k) {
    if(data[k] < 0) return (k);
    return data[k] = find(data[k]);
  }

  int size(int k) {
    return -data[find(k)];
  }

  bool same(int x, int y) {
    return find(x) == find(y);
  }
};

namespace luz {

  void solve(usize n, usize m, usize k) {
    std::vector< usize > us(m), vs(m);
    std::vector< int > ws(m);
    std::vector< bool > ls(m);

    for (usize i: rep(0, m)) {
      us[i] = input() - 1;
      vs[i] = input() - 1;
      ws[i] = input();
      ls[i] = (input<char>() == 'A');
    }

    { // reachablility
      UnionFind uf(n);
      for (usize i: rep(0, m)) {
        uf.unite(us[i], vs[i]);
      }
      for (usize v: rep(0, n)) {
        if (uf.same(0, v)) continue;
        std::cout << -1 << std::endl;
        return;
      }
    }

    auto check = [&](int lambda) {
      //                    < <cost, is_b >, idx>
      std::vector< std::pair< std::pair<int, bool>, usize > > es;

      //                    < <cost, is_a >, idx>
      std::vector< std::pair< std::pair<int, bool>, usize > > res;

      for (usize i: rep(0, m)) {
        int cost = ws[i] + (ls[i] ? lambda : 0);
         es.emplace_back(std::make_pair(cost, not ls[i]), i);
        res.emplace_back(std::make_pair(cost,     ls[i]), i);
      }

      std::sort( es.begin(),  es.end());
      std::sort(res.begin(), res.end());

      usize cnt_a0 = 0, cnt_a1 = 0;
      int mst = 0;

      {
        UnionFind dsu(n);
        for (auto [_, i]: es) {
          if (dsu.same(us[i], vs[i])) continue;
          dsu.unite(us[i], vs[i]);
          cnt_a0 += ls[i];
          mst += ws[i] + (ls[i] ? lambda : 0);
        }
      }
      {
        UnionFind dsu(n);
        for (auto [_, i]: res) {
          if (dsu.same(us[i], vs[i])) continue;
          dsu.unite(us[i], vs[i]);
          cnt_a1 += ls[i];
        }
      }

      return std::make_pair(std::make_pair(cnt_a0, cnt_a1), mst);
    };

    constexpr int inf = 1001001001;
    int ans = inf;
    for (int lambda = -105; lambda <= 105; lambda++) {
      auto [cnt, mst] = check(lambda);
      if (cnt.second <= k and k <= cnt.first) {
        chmin(ans, mst - k * lambda);
      }
    }

    if (ans == inf) ans = -1;
    std::cout << ans << std::endl;
  }

  void main_() {
    usize n, m, k;

    while (std::cin >> n >> m >> k, n) {
      solve(n, m, k);
    }
  }

} // namespace luz

int main() {
  luz::set_fast_ios();
  luz::io_set(15);

  luz::main_();
}
accuracy: 1
time_ms: 140
memory_kb: 3344
final_rank: 9

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

//constexpr long long int MOD = 1000000007;
constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-8;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

class UnionFind {
	vector<int>parent;
	vector<int>rank;
public:
	UnionFind(int num) {
		num++;
		parent.resize(num);
		rank.resize(num);
		for (int i = 0; i < num; i++) {
			parent[i] = i;
			rank[i] = 0;
		}
	}
	int Find(int node) {
		if (parent[node] == node)return node;
		else return parent[node] = Find(parent[node]);
	}
	void Unite(int u, int v) {
		u = Find(u);
		v = Find(v);
		if (u == v)return;
		if (rank[u] < rank[v])parent[u] = v;
		else {
			parent[v] = u;
			if (rank[u] == rank[v])rank[u]++;
		}
	}
	bool Check_Same(int u, int v) {
		return Find(u) == Find(v);
	}
};

struct Edge {
	int cost;
	int u, v;
	Edge(int cost, int u, int v) :cost(cost), u(u), v(v) {

	}
	bool operator<(const Edge& edge)const {
		return cost < edge.cost;
	}
};

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

	while (cin >> N >> M >> K, N) {
		vector<int>au;
		vector<int>av;
		vector<int>aw;
		vector<int>bu;
		vector<int>bv;
		vector<int>bw;
		for (int i = 0; i < M; i++) {
			int a, b, c;
			cin >> a >> b >> c;
			a--, b--;
			char ab;
			cin >> ab;
			if (ab == 'A') {
				au.push_back(a);
				av.push_back(b);
				aw.push_back(c);
			}
			else {
				bu.push_back(a);
				bv.push_back(b);
				bw.push_back(c);
			}
		}
		long long ans = LLONG_MAX;
		for (int i = -200; i <= 200; i++) {
			int score = 0;
			int comp = N;
			{
				UnionFind uf(N);
				vector<Edge>edge;
				for (int j = 0; j < au.size(); j++) {
					edge.push_back(Edge(aw[j] + i, au[j], av[j]));
				}
				for (int j = 0; j < bu.size(); j++) {
					edge.push_back(Edge(bw[j], -bu[j], -bv[j]));
				}
				reverse(edge.begin(), edge.end());
				stable_sort(edge.begin(), edge.end());
				int num = 0;
				for (auto j : edge) {
					if (uf.Check_Same(abs(j.u), abs(j.v)))continue;
					comp--;
					uf.Unite(abs(j.u), abs(j.v));
					score += j.cost;
					num += j.u + j.v > 0;
				}
				L = num;
			}
			{
				UnionFind uf(N);
				vector<Edge>edge;
				for (int j = 0; j < au.size(); j++) {
					edge.push_back(Edge(aw[j] + i, au[j], av[j]));
				}
				for (int j = 0; j < bu.size(); j++) {
					edge.push_back(Edge(bw[j], -bu[j], -bv[j]));
				}
				stable_sort(edge.begin(), edge.end());
				int num = 0;
				for (auto j : edge) {
					if (uf.Check_Same(abs(j.u), abs(j.v)))continue;
					uf.Unite(abs(j.u), abs(j.v));
					num += j.u + j.v > 0;
				}
				R = num;
			}
			if (L > R) {
				swap(L, R);
			}
			if (comp==1&&L <= K && K <= R) {
				ans = min(ans, score - i * K);
			}
		}
		if (ans == LLONG_MAX)ans = -1;
		cout << ans << endl;
	}
}
accuracy: 1
time_ms: 200
memory_kb: 3448
final_rank: 11

code_snippet: #line 1 "combinatorial_opt/test/matroid_intersection.aoj1605.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1605"
#line 2 "graph/shortest_path.hpp"
#include <algorithm>
#include <cassert>
#include <deque>
#include <fstream>
#include <functional>
#include <limits>
#include <queue>
#include <string>
#include <utility>
#include <vector>

// CUT begin
template <typename T, T INF = std::numeric_limits<T>::max() / 2, int INVALID = -1>
struct ShortestPath {
    int V, E;
    bool single_positive_weight;
    T wmin, wmax;
    std::vector<std::vector<std::pair<int, T>>> to;

    ShortestPath(int V = 0) : V(V), E(0), single_positive_weight(true), wmin(0), wmax(0), to(V) {}
    void add_edge(int s, int t, T w) {
        assert(0 <= s and s < V);
        assert(0 <= t and t < V);
        to[s].emplace_back(t, w);
        E++;
        if (w > 0 and wmax > 0 and wmax != w) single_positive_weight = false;
        wmin = std::min(wmin, w);
        wmax = std::max(wmax, w);
    }

    std::vector<T> dist;
    std::vector<int> prev;

    // Dijkstra algorithm
    // Complexity: O(E log E)
    using Pque = std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>,
                                     std::greater<std::pair<T, int>>>;
    template <class Heap = Pque> void Dijkstra(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF);
        dist[s] = 0;
        prev.assign(V, INVALID);
        Heap pq;
        pq.emplace(0, s);
        while (!pq.empty()) {
            T d;
            int v;
            std::tie(d, v) = pq.top();
            pq.pop();
            if (dist[v] < d) continue;
            for (auto nx : to[v]) {
                T dnx = d + nx.second;
                if (dist[nx.first] > dnx) {
                    dist[nx.first] = dnx, prev[nx.first] = v;
                    pq.emplace(dnx, nx.first);
                }
            }
        }
    }

    // Dijkstra algorithm, O(V^2 + E)
    void DijkstraVquad(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF);
        dist[s] = 0;
        prev.assign(V, INVALID);
        std::vector<char> fixed(V, false);
        while (true) {
            int r = INVALID;
            T dr = INF;
            for (int i = 0; i < V; i++) {
                if (!fixed[i] and dist[i] < dr) r = i, dr = dist[i];
            }
            if (r == INVALID) break;
            fixed[r] = true;
            int nxt;
            T dx;
            for (auto p : to[r]) {
                std::tie(nxt, dx) = p;
                if (dist[nxt] > dist[r] + dx) dist[nxt] = dist[r] + dx, prev[nxt] = r;
            }
        }
    }

    // Bellman-Ford algorithm
    // Complexity: O(VE)
    bool BellmanFord(int s, int nb_loop) {
        assert(0 <= s and s < V);
        dist.assign(V, INF), prev.assign(V, INVALID);
        dist[s] = 0;
        for (int l = 0; l < nb_loop; l++) {
            bool upd = false;
            for (int v = 0; v < V; v++) {
                if (dist[v] == INF) continue;
                for (auto nx : to[v]) {
                    T dnx = dist[v] + nx.second;
                    if (dist[nx.first] > dnx) dist[nx.first] = dnx, prev[nx.first] = v, upd = true;
                }
            }
            if (!upd) return true;
        }
        return false;
    }

    // Bellman-ford algorithm using queue (deque)
    // Complexity: O(VE)
    // Requirement: no negative loop
    void SPFA(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF);
        prev.assign(V, INVALID);
        std::deque<int> q;
        std::vector<char> in_queue(V);
        dist[s] = 0;
        q.push_back(s), in_queue[s] = 1;
        while (!q.empty()) {
            int now = q.front();
            q.pop_front(), in_queue[now] = 0;
            for (auto nx : to[now]) {
                T dnx = dist[now] + nx.second;
                int nxt = nx.first;
                if (dist[nxt] > dnx) {
                    dist[nxt] = dnx;
                    if (!in_queue[nxt]) {
                        if (q.size() and dnx < dist[q.front()]) { // Small label first optimization
                            q.push_front(nxt);
                        } else {
                            q.push_back(nxt);
                        }
                        prev[nxt] = now, in_queue[nxt] = 1;
                    }
                }
            }
        }
    }

    void ZeroOneBFS(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF), prev.assign(V, INVALID);
        dist[s] = 0;
        std::deque<int> que;
        que.push_back(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop_front();
            for (auto nx : to[v]) {
                T dnx = dist[v] + nx.second;
                if (dist[nx.first] > dnx) {
                    dist[nx.first] = dnx, prev[nx.first] = v;
                    if (nx.second) {
                        que.push_back(nx.first);
                    } else {
                        que.push_front(nx.first);
                    }
                }
            }
        }
    }

    bool dag_solver(int s) {
        assert(0 <= s and s < V);
        std::vector<int> indeg(V, 0);
        std::queue<int> que;
        que.push(s);
        while (que.size()) {
            int now = que.front();
            que.pop();
            for (auto nx : to[now]) {
                indeg[nx.first]++;
                if (indeg[nx.first] == 1) que.push(nx.first);
            }
        }
        dist.assign(V, INF), prev.assign(V, INVALID);
        dist[s] = 0;
        que.push(s);
        while (que.size()) {
            int now = que.front();
            que.pop();
            for (auto nx : to[now]) {
                indeg[nx.first]--;
                if (dist[nx.first] > dist[now] + nx.second)
                    dist[nx.first] = dist[now] + nx.second, prev[nx.first] = now;
                if (indeg[nx.first] == 0) que.push(nx.first);
            }
        }
        return *max_element(indeg.begin(), indeg.end()) == 0;
    }

    // Retrieve a sequence of vertex ids that represents shortest path [s, ..., goal]
    // If not reachable to goal, return {}
    std::vector<int> retrieve_path(int goal) const {
        assert(int(prev.size()) == V);
        assert(0 <= goal and goal < V);
        if (dist[goal] == INF) return {};
        std::vector<int> ret{goal};
        while (prev[goal] != INVALID) {
            goal = prev[goal];
            ret.push_back(goal);
        }
        std::reverse(ret.begin(), ret.end());
        return ret;
    }

    void solve(int s) {
        if (wmin >= 0) {
            if (single_positive_weight) {
                ZeroOneBFS(s);
            } else {
                if ((long long)V * V < (E << 4)) {
                    DijkstraVquad(s);
                } else {
                    Dijkstra(s);
                }
            }
        } else {
            BellmanFord(s, V);
        }
    }

    // Warshall-Floyd algorithm
    // Complexity: O(E + V^3)
    std::vector<std::vector<T>> dist2d;
    void WarshallFloyd() {
        dist2d.assign(V, std::vector<T>(V, INF));
        for (int i = 0; i < V; i++) {
            dist2d[i][i] = 0;
            for (auto p : to[i]) dist2d[i][p.first] = std::min(dist2d[i][p.first], p.second);
        }
        for (int k = 0; k < V; k++) {
            for (int i = 0; i < V; i++) {
                if (dist2d[i][k] == INF) continue;
                for (int j = 0; j < V; j++) {
                    if (dist2d[k][j] == INF) continue;
                    dist2d[i][j] = std::min(dist2d[i][j], dist2d[i][k] + dist2d[k][j]);
                }
            }
        }
    }

    void dump_graphviz(std::string filename = "shortest_path") const {
        std::ofstream ss(filename + ".DOT");
        ss << "digraph{\n";
        for (int i = 0; i < V; i++) {
            for (const auto &e : to[i])
                ss << i << "->" << e.first << "[label=" << e.second << "];\n";
        }
        ss << "}\n";
        ss.close();
        return;
    }
};
#line 5 "combinatorial_opt/matroid_intersection.hpp"

// CUT begin
// (Min weight) matroid intersection solver
// Algorithm based on http://dopal.cs.uec.ac.jp/okamotoy/lect/2015/matroid/
// Complexity: O(CE^2 + E^3) (C : circuit query, non-weighted)
template <class M1, class M2, class T = int>
std::vector<bool> MatroidIntersection(M1 matroid1, M2 matroid2, std::vector<T> weights = {}) {
    using State = std::vector<bool>;
    using Element = int;
    assert(matroid1.size() == matroid2.size());
    const int M = matroid1.size();

    for (auto &x : weights) x *= M + 1;
    if (weights.empty()) weights.assign(M, 0);

    const Element gs = M, gt = M + 1;
    State I(M);

    while (true) {
        ShortestPath<T> sssp(M + 2);
        matroid1.set(I);
        matroid2.set(I);
        for (int e = 0; e < M; e++) {
            if (I[e]) continue;
            auto c1 = matroid1.circuit(e), c2 = matroid2.circuit(e);
            if (c1.empty()) sssp.add_edge(e, gt, 0);
            for (Element f : c1) {
                if (f != e) sssp.add_edge(e, f, -weights[f] + 1);
            }
            if (c2.empty()) sssp.add_edge(gs, e, weights[e] + 1);
            for (Element f : c2) {
                if (f != e) sssp.add_edge(f, e, weights[e] + 1);
            }
        }
        sssp.solve(gs);
        auto aug_path = sssp.retrieve_path(gt);
        if (aug_path.empty()) break;
        for (auto e : aug_path) {
            if (e != gs and e != gt) I[e] = !I[e];
        }
    }
    return I;
}
#line 5 "combinatorial_opt/matroids/graphic_matroid.hpp"

// GraphicMatroid: subgraph of undirected graphs, without loops
class GraphicMatroid {
    using Vertex = int;
    using Element = int;
    int M;
    int V; // # of vertices of graph
    std::vector<std::vector<std::pair<Vertex, Element>>> to;
    std::vector<std::pair<Vertex, Vertex>> edges;
    std::vector<Element> backtrack;
    std::vector<Vertex> vprev;
    std::vector<int> depth, root;

public:
    GraphicMatroid(int V, const std::vector<std::pair<Vertex, Vertex>> &edges_)
        : M(edges_.size()), V(V), to(V), edges(edges_) {
        for (int e = 0; e < int(edges_.size()); e++) {
            int u = edges_[e].first, v = edges_[e].second;
            assert(0 <= u and u < V);
            assert(0 <= v and v < V);
            if (u != v) {
                to[u].emplace_back(v, e);
                to[v].emplace_back(u, e);
            }
        }
    }
    int size() const { return M; }

    std::vector<Vertex> que;
    template <class State> void set(State I) {
        assert(int(I.size()) == M);
        backtrack.assign(V, -1);
        vprev.assign(V, -1);
        depth.assign(V, -1);
        root.assign(V, -1);
        que.resize(V);
        int qb = 0, qe = 0;
        for (Vertex i = 0; i < V; i++) {
            if (backtrack[i] >= 0) continue;
            que[qb = 0] = i, qe = 1, depth[i] = 0;
            while (qb < qe) {
                Vertex now = que[qb++];
                root[now] = i;
                for (auto nxt : to[now]) {
                    if (depth[nxt.first] < 0 and I[nxt.second]) {
                        backtrack[nxt.first] = nxt.second;
                        vprev[nxt.first] = now;
                        depth[nxt.first] = depth[now] + 1;
                        que[qe++] = nxt.first;
                    }
                }
            }
        }
    }

    std::vector<Element> circuit(const Element e) const {
        assert(0 <= e and e < M);
        Vertex s = edges[e].first, t = edges[e].second;
        if (root[s] != root[t]) return {};
        std::vector<Element> ret{e};
        auto step = [&](Vertex &i) { ret.push_back(backtrack[i]), i = vprev[i]; };
        int ddepth = depth[s] - depth[t];
        for (; ddepth > 0; --ddepth) step(s);
        for (; ddepth < 0; ++ddepth) step(t);
        while (s != t) step(s), step(t);
        return ret;
    }
};
#line 4 "combinatorial_opt/matroids/partition_matroid.hpp"

// Partition matroid (partitional matroid) : direct sum of uniform matroids
class PartitionMatroid {
    using Element = int;
    int M;
    std::vector<std::vector<Element>> parts;
    std::vector<int> belong;
    std::vector<int> R;
    std::vector<int> cnt;
    std::vector<std::vector<Element>> circuits;

public:
    // parts: partition of [0, 1, ..., M - 1]
    // R: only R[i] elements from parts[i] can be chosen for each i.
    PartitionMatroid(int M, const std::vector<std::vector<int>> &parts_, const std::vector<int> &R_)
        : M(M), parts(parts_), belong(M, -1), R(R_) {
        assert(parts.size() == R.size());
        for (int i = 0; i < int(parts.size()); i++) {
            for (Element e : parts[i]) belong[e] = i;
        }
        for (Element e = 0; e < M; e++) {
            // assert(belong[e] != -1);
            if (belong[e] == -1) {
                belong[e] = parts.size();
                parts.push_back({e});
                R.push_back(1);
            }
        }
    }
    int size() const { return M; }

    template <class State> void set(const State &I) {
        cnt = R;
        for (int e = 0; e < M; e++) {
            if (I[e]) cnt[belong[e]]--;
        }
        circuits.assign(cnt.size(), {});
        for (int e = 0; e < M; e++) {
            if (I[e] and cnt[belong[e]] == 0) circuits[belong[e]].push_back(e);
        }
    }

    std::vector<Element> circuit(const Element e) const {
        assert(0 <= e and e < M);
        int p = belong[e];
        if (cnt[p] == 0) {
            auto ret = circuits[p];
            ret.push_back(e);
            return ret;
        }
        return {};
    }
};
#line 5 "combinatorial_opt/test/matroid_intersection.aoj1605.test.cpp"
#include <iostream>
#include <numeric>
#line 9 "combinatorial_opt/test/matroid_intersection.aoj1605.test.cpp"
using namespace std;

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    while (true) {
        int N, M, K;
        cin >> N >> M >> K;
        if (N == 0) break;
        vector<vector<int>> partition(2);
        vector<int> R{K, N - 1 - K};
        vector<pair<int, int>> edges;
        vector<int> weights;
        for (int e = 0; e < M; ++e) {
            int u, v, w;
            char l;
            cin >> u >> v >> w >> l;
            --u, --v;
            partition[l == 'B'].push_back(e);
            edges.emplace_back(u, v);
            weights.push_back(w);
        }
        PartitionMatroid M1(edges.size(), partition, R);
        GraphicMatroid M2(N, edges);
        vector<bool> ret = MatroidIntersection(M1, M2, weights);
        int ne = accumulate(ret.begin(), ret.end(), 0);
        if (ne < N - 1) {
            cout << "-1\n";
        } else {
            int sum = 0;
            for (int e = 0; e < M; ++e) sum += ret[e] * weights[e];
            cout << sum << '\n';
        }
    }
}
accuracy: 1
time_ms: 360
memory_kb: 4072
final_rank: 16

code_snippet: #line 2 "library/bits/stdc++.h"

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
#line 2 "Source.cpp"
using namespace std;

#define REP(a, b) for (long long a = 0; a < b; ++a)
#define ll long long
#define ld long double
#define ALL(x) begin(x), end(x)

#line 1 "library/atcoder/dsu.hpp"



#line 5 "library/atcoder/dsu.hpp"
#include <cassert>
#line 7 "library/atcoder/dsu.hpp"

namespace atcoder {

// Implement (union by size) + (path compression)
// Reference:
// Zvi Galil and Giuseppe F. Italiano,
// Data structures and algorithms for disjoint set union problems
struct dsu {
  public:
    dsu() : _n(0) {}
    explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

}  // namespace atcoder


#line 10 "Source.cpp"

#define int long long
void solve()
{
  int n, m, k;
  cin >> n >> m >> k;
  if (n == 0)
    exit(0);
  vector<tuple<int, int, int, int>> edges;
  REP(i, m)
  {
    int a, b, c;
    string d;
    cin >> a >> b >> c >> d;
    a--;
    b--;
    edges.push_back({c, a, b, d[0] - 'A'});
  }
  sort(ALL(edges));
  atcoder::dsu graph(n);
  vector<tuple<int, int, int, int>> current_edges;
  for (int i = 0; i < m; ++i)
  {
    if (graph.same(get<1>(edges[i]), get<2>(edges[i])))
      continue;
    current_edges.push_back(edges[i]);
    graph.merge(get<1>(edges[i]), get<2>(edges[i]));
    k -= 1 - get<3>(edges[i]);
    edges.erase(edges.begin() + i);
    i--;
  }

  REP(i, n)
  {
    if (!graph.same(i, 0))
    {
      cout << -1 << endl;
      return;
    }
  }
  while (k != 0)
  {
    tuple<int, int, int> target = make_tuple(1e18, 0, 0);
    REP(i, current_edges.size())
    {
      if (k < 0)
      {
        if (get<3>(current_edges[i]) == 1)
          continue;
      }
      else
      {
        if (get<3>(current_edges[i]) == 0)
          continue;
      }

      atcoder::dsu graph(n);
      REP(q, current_edges.size())
      {
        if (i == q)
          continue;
        graph.merge(get<1>(current_edges[q]), get<2>(current_edges[q]));
      }

      REP(q, edges.size())
      {
        if (get<3>(edges[q]) == get<3>(current_edges[i]))
          continue;
        if (graph.same(get<1>(edges[q]), get<2>(edges[q])))
          continue;
        tuple<int, int, int> now;
        get<0>(now) = get<0>(edges[q]) - get<0>(current_edges[i]);
        get<1>(now) = i;
        get<2>(now) = q;
        if (get<0>(now) < get<0>(target))
        {
          target = now;
        }
        break;
      }
    }
    if (get<0>(target) == 1e18)
    {
      cout << -1 << endl;
      return;
    }
    swap(current_edges[get<1>(target)], edges[get<2>(target)]);
    if (k > 0)
      k--;
    else
      k++;
    sort(ALL(current_edges));
    sort(ALL(edges));
  }
  int ans = 0;
  for (auto x : current_edges)
  {
    ans += get<0>(x);
  }
  cout << ans << endl;
}

#undef int
int main()
{
  iostream::sync_with_stdio(false);
  cout << fixed << setprecision(100);
  while (true)
    solve();
}
accuracy: 1
time_ms: 140
memory_kb: 3412
final_rank: 10

code_snippet: #include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <forward_list>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using lint = long long;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_;
#define ALL(x) (x).begin(), (x).end()
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--)
#define REP(i, n) FOR(i,0,n)
#define IREP(i, n) IFOR(i,0,n)
template <typename T, typename V>
void ndarray(vector<T>& vec, const V& val, int len) { vec.assign(len, val); }
template <typename T, typename V, typename... Args> void ndarray(vector<T>& vec, const V& val, int len, Args... args) { vec.resize(len), for_each(begin(vec), end(vec), [&](T& v) { ndarray(v, val, args...); }); }
template <typename T> bool chmax(T &m, const T q) { return m < q ? (m = q, true) : false; }
template <typename T> bool chmin(T &m, const T q) { return m > q ? (m = q, true) : false; }
int floor_lg(long long x) { return x <= 0 ? -1 : 63 - __builtin_clzll(x); }
template <typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); }
template <typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); }
template <typename T> vector<T> sort_unique(vector<T> vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; }
template <typename T> int arglb(const std::vector<T> &v, const T &x) { return std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), x)); }
template <typename T> int argub(const std::vector<T> &v, const T &x) { return std::distance(v.begin(), std::upper_bound(v.begin(), v.end(), x)); }
template <typename T> istream &operator>>(istream &is, vector<T> &vec) { for (auto &v : vec) is >> v; return is; }
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <typename T, size_t sz> ostream &operator<<(ostream &os, const array<T, sz> &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; }
#if __cplusplus >= 201703L
template <typename... T> istream &operator>>(istream &is, tuple<T...> &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; }
template <typename... T> ostream &operator<<(ostream &os, const tuple<T...> &tpl) { os << '('; std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os << ')'; }
#endif
template <typename T> ostream &operator<<(ostream &os, const deque<T> &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; }
template <typename T> ostream &operator<<(ostream &os, const set<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T, typename TH> ostream &operator<<(ostream &os, const unordered_set<T, TH> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T> ostream &operator<<(ostream &os, const multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; }
template <typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa) { os << '(' << pa.first << ',' << pa.second << ')'; return os; }
template <typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
template <typename TK, typename TV, typename TH> ostream &operator<<(ostream &os, const unordered_map<TK, TV, TH> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; }
#ifdef HITONANODE_LOCAL
const string COLOR_RESET = "\033[0m", BRIGHT_GREEN = "\033[1;32m", BRIGHT_RED = "\033[1;31m", BRIGHT_CYAN = "\033[1;36m", NORMAL_CROSSED = "\033[0;9;37m", RED_BACKGROUND = "\033[1;41m", NORMAL_FAINT = "\033[0;2m";
#define dbg(x) cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << endl
#define dbgif(cond, x) ((cond) ? cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << endl : cerr)
#else
#define dbg(x) (x)
#define dbgif(cond, x) 0
#endif

template <typename T, T INF = std::numeric_limits<T>::max() / 2, int INVALID = -1> struct ShortestPath {
    int V, E;
    bool single_positive_weight;
    T wmin, wmax;
    std::vector<std::vector<std::pair<int, T>>> to;

    ShortestPath(int V = 0) : V(V), E(0), single_positive_weight(true), wmin(0), wmax(0), to(V) {}
    void add_edge(int s, int t, T w) {
        assert(0 <= s and s < V);
        assert(0 <= t and t < V);
        to[s].emplace_back(t, w);
        E++;
        if (w > 0 and wmax > 0 and wmax != w) single_positive_weight = false;
        wmin = std::min(wmin, w);
        wmax = std::max(wmax, w);
    }

    std::vector<T> dist;
    std::vector<int> prev;

    // Dijkstra algorithm
    // Complexity: O(E log E)
    using Pque = std::priority_queue<std::pair<T, int>, std::vector<std::pair<T, int>>, std::greater<std::pair<T, int>>>;
    template <class Heap = Pque> void Dijkstra(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF);
        dist[s] = 0;
        prev.assign(V, INVALID);
        Heap pq;
        pq.emplace(0, s);
        while (!pq.empty()) {
            T d;
            int v;
            std::tie(d, v) = pq.top();
            pq.pop();
            if (dist[v] < d) continue;
            for (auto nx : to[v]) {
                T dnx = d + nx.second;
                if (dist[nx.first] > dnx) {
                    dist[nx.first] = dnx, prev[nx.first] = v;
                    pq.emplace(dnx, nx.first);
                }
            }
        }
    }

    // Dijkstra algorithm, O(V^2 + E)
    void DijkstraVquad(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF);
        dist[s] = 0;
        prev.assign(V, INVALID);
        std::vector<char> fixed(V, false);
        while (true) {
            int r = INVALID;
            T dr = INF;
            for (int i = 0; i < V; i++) {
                if (!fixed[i] and dist[i] < dr) r = i, dr = dist[i];
            }
            if (r == INVALID) break;
            fixed[r] = true;
            int nxt;
            T dx;
            for (auto p : to[r]) {
                std::tie(nxt, dx) = p;
                if (dist[nxt] > dist[r] + dx) dist[nxt] = dist[r] + dx, prev[nxt] = r;
            }
        }
    }

    // Bellman-Ford algorithm
    // Complexity: O(VE)
    bool BellmanFord(int s, int nb_loop) {
        assert(0 <= s and s < V);
        dist.assign(V, INF), prev.assign(V, INVALID);
        dist[s] = 0;
        for (int l = 0; l < nb_loop; l++) {
            bool upd = false;
            for (int v = 0; v < V; v++) {
                if (dist[v] == INF) continue;
                for (auto nx : to[v]) {
                    T dnx = dist[v] + nx.second;
                    if (dist[nx.first] > dnx) dist[nx.first] = dnx, prev[nx.first] = v, upd = true;
                }
            }
            if (!upd) return true;
        }
        return false;
    }

    // Bellman-ford algorithm using queue (deque)
    // Complexity: O(VE)
    // Requirement: no negative loop
    void SPFA(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF);
        prev.assign(V, INVALID);
        std::deque<int> q;
        std::vector<char> in_queue(V);
        dist[s] = 0;
        q.push_back(s), in_queue[s] = 1;
        while (!q.empty()) {
            int now = q.front();
            q.pop_front(), in_queue[now] = 0;
            for (auto nx : to[now]) {
                T dnx = dist[now] + nx.second;
                int nxt = nx.first;
                if (dist[nxt] > dnx) {
                    dist[nxt] = dnx;
                    if (!in_queue[nxt]) {
                        if (q.size() and dnx < dist[q.front()]) { // Small label first optimization
                            q.push_front(nxt);
                        } else {
                            q.push_back(nxt);
                        }
                        prev[nxt] = now, in_queue[nxt] = 1;
                    }
                }
            }
        }
    }

    void ZeroOneBFS(int s) {
        assert(0 <= s and s < V);
        dist.assign(V, INF), prev.assign(V, INVALID);
        dist[s] = 0;
        std::deque<int> que;
        que.push_back(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop_front();
            for (auto nx : to[v]) {
                T dnx = dist[v] + nx.second;
                if (dist[nx.first] > dnx) {
                    dist[nx.first] = dnx, prev[nx.first] = v;
                    if (nx.second) {
                        que.push_back(nx.first);
                    } else {
                        que.push_front(nx.first);
                    }
                }
            }
        }
    }

    bool dag_solver(int s) {
        assert(0 <= s and s < V);
        std::vector<int> indeg(V, 0);
        std::queue<int> que;
        que.push(s);
        while (que.size()) {
            int now = que.front();
            que.pop();
            for (auto nx : to[now]) {
                indeg[nx.first]++;
                if (indeg[nx.first] == 1) que.push(nx.first);
            }
        }
        dist.assign(V, INF), prev.assign(V, INVALID);
        dist[s] = 0;
        que.push(s);
        while (que.size()) {
            int now = que.front();
            que.pop();
            for (auto nx : to[now]) {
                indeg[nx.first]--;
                if (dist[nx.first] > dist[now] + nx.second)
                    dist[nx.first] = dist[now] + nx.second, prev[nx.first] = now;
                if (indeg[nx.first] == 0) que.push(nx.first);
            }
        }
        return *max_element(indeg.begin(), indeg.end()) == 0;
    }

    // Retrieve a sequence of vertex ids that represents shortest path [s, ..., goal]
    // If not reachable to goal, return {}
    std::vector<int> retrieve_path(int goal) const {
        assert(int(prev.size()) == V);
        assert(0 <= goal and goal < V);
        if (dist[goal] == INF) return {};
        std::vector<int> ret{goal};
        while (prev[goal] != INVALID) {
            goal = prev[goal];
            ret.push_back(goal);
        }
        std::reverse(ret.begin(), ret.end());
        return ret;
    }

    void solve(int s) {
        if (wmin >= 0) {
            if (single_positive_weight) {
                ZeroOneBFS(s);
            } else {
                if ((long long)V * V < (E << 4)) {
                    DijkstraVquad(s);
                } else {
                    Dijkstra(s);
                }
            }
        } else {
            BellmanFord(s, V);
        }
    }

    // Warshall-Floyd algorithm
    // Complexity: O(E + V^3)
    std::vector<std::vector<T>> dist2d;
    void WarshallFloyd() {
        dist2d.assign(V, std::vector<T>(V, INF));
        for (int i = 0; i < V; i++) {
            dist2d[i][i] = 0;
            for (auto p : to[i]) dist2d[i][p.first] = std::min(dist2d[i][p.first], p.second);
        }
        for (int k = 0; k < V; k++) {
            for (int i = 0; i < V; i++) {
                if (dist2d[i][k] == INF) continue;
                for (int j = 0; j < V; j++) {
                    if (dist2d[k][j] == INF) continue;
                    dist2d[i][j] = std::min(dist2d[i][j], dist2d[i][k] + dist2d[k][j]);
                }
            }
        }
    }

    void dump_graphviz(std::string filename = "shortest_path") const {
        std::ofstream ss(filename + ".DOT");
        ss << "digraph{\n";
        for (int i = 0; i < V; i++) {
            for (const auto &e : to[i]) ss << i << "->" << e.first << "[label=" << e.second << "];\n";
        }
        ss << "}\n";
        ss.close();
        return;
    }
};


// Partition matroid (partitional matroid) : direct sum of uniform matroids
class PartitionMatroid {
    using Element = int;
    int M;
    std::vector<std::vector<Element>> parts;
    std::vector<int> belong;
    std::vector<int> R;
    std::vector<int> cnt;
    std::vector<std::vector<Element>> circuits;

public:
    // parts: partition of [0, 1, ..., M - 1]
    // R: only R[i] elements from parts[i] can be chosen for each i.
    PartitionMatroid(int M, const std::vector<std::vector<int>> &parts_, const std::vector<int> &R_)
        : M(M), parts(parts_), belong(M, -1), R(R_) {
        assert(parts.size() == R.size());
        for (int i = 0; i < int(parts.size()); i++) {
            for (Element e : parts[i]) belong[e] = i;
        }
        for (Element e = 0; e < M; e++) {
            // assert(belong[e] != -1);
            if (belong[e] == -1) {
                belong[e] = parts.size();
                parts.push_back({e});
                R.push_back(1);
            }
        }
    }
    int size() const { return M; }

    template <class State> void set(const State &I) {
        cnt = R;
        for (int e = 0; e < M; e++) {
            if (I[e]) cnt[belong[e]]--;
        }
        circuits.assign(cnt.size(), {});
        for (int e = 0; e < M; e++) {
            if (I[e] and cnt[belong[e]] == 0) circuits[belong[e]].push_back(e);
        }
    }

    std::vector<Element> circuit(const Element e) const {
        assert(0 <= e and e < M);
        int p = belong[e];
        if (cnt[p] == 0) {
            auto ret = circuits[p];
            ret.push_back(e);
            return ret;
        }
        return {};
    }
};

// GraphicMatroid: subgraph of undirected graphs, without loops
class GraphicMatroid {
    using Vertex = int;
    using Element = int;
    int M;
    int V; // # of vertices of graph
    std::vector<std::vector<std::pair<Vertex, Element>>> to;
    std::vector<std::pair<Vertex, Vertex>> edges;
    std::vector<Element> backtrack;
    std::vector<Vertex> vprev;
    std::vector<int> depth, root;

public:
    GraphicMatroid(int V, const std::vector<std::pair<Vertex, Vertex>> &edges_)
        : M(edges_.size()), V(V), to(V), edges(edges_) {
        for (int e = 0; e < int(edges_.size()); e++) {
            int u = edges_[e].first, v = edges_[e].second;
            assert(0 <= u and u < V);
            assert(0 <= v and v < V);
            if (u != v) {
                to[u].emplace_back(v, e);
                to[v].emplace_back(u, e);
            }
        }
    }
    int size() const { return M; }

    std::vector<Vertex> que;
    template <class State> void set(State I) {
        assert(int(I.size()) == M);
        backtrack.assign(V, -1);
        vprev.assign(V, -1);
        depth.assign(V, -1);
        root.assign(V, -1);
        que.resize(V);
        int qb = 0, qe = 0;
        for (Vertex i = 0; i < V; i++) {
            if (backtrack[i] >= 0) continue;
            que[qb = 0] = i, qe = 1, depth[i] = 0;
            while (qb < qe) {
                Vertex now = que[qb++];
                root[now] = i;
                for (auto nxt : to[now]) {
                    if (depth[nxt.first] < 0 and I[nxt.second]) {
                        backtrack[nxt.first] = nxt.second;
                        vprev[nxt.first] = now;
                        depth[nxt.first] = depth[now] + 1;
                        que[qe++] = nxt.first;
                    }
                }
            }
        }
    }

    std::vector<Element> circuit(const Element e) const {
        assert(0 <= e and e < M);
        Vertex s = edges[e].first, t = edges[e].second;
        if (root[s] != root[t]) return {};
        std::vector<Element> ret{e};
        auto step = [&](Vertex &i) { ret.push_back(backtrack[i]), i = vprev[i]; };
        int ddepth = depth[s] - depth[t];
        for (; ddepth > 0; --ddepth) step(s);
        for (; ddepth < 0; ++ddepth) step(t);
        while (s != t) step(s), step(t);
        return ret;
    }
};

// (Min weight) matroid intersection solver
// Algorithm based on http://dopal.cs.uec.ac.jp/okamotoy/lect/2015/matroid/
// Complexity: O(CE^2 + E^3) (C : circuit query, non-weighted)
template <class M1, class M2, class T = int>
std::vector<bool> MatroidIntersection(M1 matroid1, M2 matroid2, std::vector<T> weights = {}) {
    using State = std::vector<bool>;
    using Element = int;
    assert(matroid1.size() == matroid2.size());
    const int M = matroid1.size();

    for (auto &x : weights) x *= M + 1;
    if (weights.empty()) weights.assign(M, 0);

    const Element gs = M, gt = M + 1;
    State I(M);

    while (true) {
        ShortestPath<T> sssp(M + 2);
        matroid1.set(I);
        matroid2.set(I);
        for (int e = 0; e < M; e++) {
            if (I[e]) continue;
            auto c1 = matroid1.circuit(e), c2 = matroid2.circuit(e);
            if (c1.empty()) sssp.add_edge(e, gt, 0);
            for (Element f : c1) {
                if (f != e) sssp.add_edge(e, f, -weights[f] + 1);
            }
            if (c2.empty()) sssp.add_edge(gs, e, weights[e] + 1);
            for (Element f : c2) {
                if (f != e) sssp.add_edge(f, e, weights[e] + 1);
            }
        }
        sssp.solve(gs);
        auto aug_path = sssp.retrieve_path(gt);
        if (aug_path.empty()) break;
        for (auto e : aug_path) {
            if (e != gs and e != gt) I[e] = !I[e];
        }
    }
    return I;
}



int main() {
    while (true) {
        int N, M, K;
        cin >> N >> M >> K;
        if (N == 0) break;
        vector<vector<int>> partition(2);
        vector<int> R{K, N - 1 - K};
        vector<pint> edges;
        vector<int> weights;
        REP(e, M) {
            int u, v, w;
            char l;
            cin >> u >> v >> w >> l;
            --u, --v;
            partition[l == 'B'].push_back(e);
            edges.emplace_back(u, v);
            weights.push_back(w);
        }
        PartitionMatroid M1(M, partition, R);
        GraphicMatroid M2(N, edges);
        vector<bool> ret = MatroidIntersection(M1, M2, weights);
        int ne = accumulate(ret.begin(), ret.end(), 0);
        if (ne < N - 1) {
            cout << "-1\n";
        } else {
            int sum = 0;
            for (int e = 0; e < M; ++e) sum += ret[e] * weights[e];
            cout << sum << '\n';
        }
    }
}
accuracy: 1
time_ms: 360
memory_kb: 4144
final_rank: 17

code_snippet: #include<cstdio>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<ll, P> Q;
constexpr ll INF = 1000000000000000LL;
constexpr Q QINF = Q(INF+10, P(INF, INF));
constexpr Q QINF2 = Q(-INF, P(INF, INF));

class UnionFind {
  vector<ll> par, rank; // par > 0: number, par < 0: -par
public:
  UnionFind(ll n) : par(n, 1), rank(n, 0) {}
  ll getSize(ll x) {
    return par[find(x)];
  }
  ll find(ll x) {
    if (par[x] > 0) return x;
    return -(par[x] = -find(-par[x]));
  }
  void merge(ll x, ll y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[y] += par[x];
      par[x] = -y;
    } else {
      par[x] += par[y];
      par[y] = -x;
      if (rank[x] == rank[y]) rank[x]++;
    }
  }
  bool isSame(ll x, ll y) {
    return find(x) == find(y);
  }
};


ll n, m, k, u, v, w;
char l[2];
set<P> e[200];

Q dfs(ll now, ll to, ll par) {
  if (now == to) return QINF2;
  for (P p : e[now]) if (p.first != par) {
    Q q = dfs(p.first, to, now);
    if (q.first != INF + 10) {
      return max(q, Q(p.second, P(now, p.first)));
    }
  }
  return QINF;
}

int main() {
  while (scanf("%lld%lld%lld", &n, &m, &k), n) {
    ll ans = 0;
    vector<Q> ea, eb;
    set<Q> rest;
    for (ll i = 0; i < n; i++) e[i].clear();
    for (ll i = 0; i < m; i++) {
      scanf("%lld%lld%lld%s", &u, &v, &w, l);
      if (l[0] == 'A') ea.push_back(Q(w, P(u-1, v-1)));
      else eb.push_back(Q(w, P(u-1, v-1)));
    }
    sort(ea.begin(), ea.end());
    sort(eb.begin(), eb.end());
    UnionFind uf(n);
    for (Q q : eb) {
      u = q.second.first, v = q.second.second, w = q.first;
      if (uf.isSame(u, v)) continue;
      ans += w;
      uf.merge(u, v);
      e[u].insert(P(v, w));
      e[v].insert(P(u, w));
    }
    for (Q q : ea) {
      u = q.second.first, v = q.second.second, w = q.first;
      if (uf.isSame(u, v)) {
        rest.insert(Q(w, P(u, v)));
        continue;
      }
      ans += w;
      uf.merge(u, v);
      e[u].insert(P(v, -INF));
      e[v].insert(P(u, -INF));
      k--;
    }
    if (uf.getSize(0) != n or k < 0 or k > (ll)rest.size()) {
      printf("-1\n");
      continue;
    }
    for (ll i = 0; i < k; i++) {
      ll mn = INF;
      Q result, result2;
      for (Q q : rest) {
        u = q.second.first, v = q.second.second, w = q.first;
        Q t = dfs(u, v, -1);
        if (t.first == -INF) continue;
        ll tmp = w - t.first;
        if (mn > tmp) {
          mn = tmp;
          result = q;
          result2 = t;
        }
      }
      if (mn == INF) {
        ans = -1;
        break;
      }
      ans += mn;
      u = result.second.first, v = result.second.second, w = result.first;
      e[u].insert(P(v, -INF));
      e[v].insert(P(u, -INF));
      u = result2.second.first, v = result2.second.second, w = result2.first;
      e[u].erase(P(v, w));
      e[v].erase(P(u, w));
      rest.erase(result);
    }
    printf("%lld\n", ans);
  }
}
accuracy: 1
time_ms: 160
memory_kb: 2988
final_rank: 8