//感觉刘汝佳老师的思维真的太厉害了orz
/*摘录书上的一段话: 只需一个小小的优化即可降低时间复杂度:先求一次原图(不购买任何套餐)的最小生
成树,得到n-1条边,然后每次枚举完套餐后只考虑套餐中的边和这n-1条边,则枚举套餐之
后再求最小生成树时,图上的边已经寥寥无几。
为什么可以这样呢?首先回顾一下,在Kruskal算法中,哪些边不会进入最小生成树。答
案是:两端已经属于同一个连通分量的边。买了套餐以后,相当于一些边的权变为0,而对
于不在套餐中的每条边e,排序在e之前的边一个都没少,反而可能多了一些权值为0的边,
所以在原图Kruskal时被“扔掉”的边,在后面的Kruskal中也一样会被扔掉。*/

// UVa1151 Buy or Build
// Rujia Liu
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

 + ;
;
int n;
int x[maxn], y[maxn], cost[maxq];
vector<int> subn[maxq];

int pa[maxn];
int findset(int x) { return pa[x] != x ? pa[x] = findset(pa[x]) : x; }

struct Edge {
  int u, v, d;
  Edge(int u, int v, int d):u(u),v(v),d(d) {}
  bool operator < (const Edge& rhs) const {
    return d < rhs.d;
  }
};

// initialize pa and sort e before calling this method
// cnt is the current number of components
int MST(int cnt, const vector<Edge>& e, vector<Edge>& used) {  //找出原图跑一边kruskal之后用过的边
  ) ;
  int m = e.size();
  ;
  used.clear();
  ; i < m; i++) {
    int u = findset(e[i].u), v = findset(e[i].v);
    int d = e[i].d;
    if(u != v) {
      pa[u] = v;
      ans += d;
      used.push_back(e[i]);
      ) break;
    }
  }
  return ans;
}

int main() {
  int T, q;
  scanf("%d", &T);
  while(T--) {
    scanf("%d%d", &n, &q);
    ; i < q; i++) {
      int cnt;
      scanf("%d%d", &cnt, &cost[i]);
      subn[i].clear();
      while(cnt--) {
        int u;
        scanf("%d", &u);
        subn[i].push_back(u-);
      }
    }
    ; i < n; i++) scanf("%d%d", &x[i], &y[i]);

    vector<Edge> e, need;
    ; i < n; i++)
      ; j < n; j++) {
        int c = (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]);
        e.push_back(Edge(i, j, c));
      }

    ; i < n; i++) pa[i] = i;
    sort(e.begin(), e.end());

    int ans = MST(n, e, need);
    ; mask < (<<q); mask++) {  //枚举套餐,二进制法
      // union cities in the same sub-network
      ; i < n; i++) pa[i] = i;
      ;
      ; i < q; i++) <<i)) {
        c += cost[i];
        ; j < subn[i].size(); j++) {
          ]);
          if(u != v) { pa[u] = v; cnt--; }
        }
      }
      vector<Edge> dummy;
      ans = min(ans, c + MST(cnt, need, dummy));
    }
    printf("%d\n", ans);
    if(T) printf("\n");
  }
  ;
}
04-30 19:45