If the graph is bipartite, the answer is . Otherwise, let
for each vertex , the same as "Sum of Distances" from the January contest. Also define
For convenience, define to be the set of all nodes with .
A graph having equivalent to that of the given graph must have edges adjacent to vertex satisfying at least one of the following conditions for each (the condition is slightly different for vertex since ).
Edges that are not type A, B, or C edges cannot exist in the graph.
We can look at each layer (vertices with a fixed ) independently, as edges of type A are only relevant to the vertex in the higher layer, and edges of type B and C are between vertices in the same layer. For a given layer, let's satisfy the constraints in increasing order of .
We'll describe two ways of doing this, of which the second approach is sufficient for full credit.
Suppose that we are currently deciding which edges to construct involving . For simplicity, we'll only deal with the case that and (for the other cases, see the code for details). Our goal is to satisfy one of the first two conditions for each vertex .
Approach 1: Define:
Then we'll need to add additional edges of type A.
These observations are sufficient for an DP. Store for each and transition to for each . See my function below for details:
#include <bits/stdc++.h> using namespace std; using ll = long long; using db = long double; // or double, if TL is tight using str = string; // yay python! using pi = pair<int,int>; using pl = pair<ll,ll>; using pd = pair<db,db>; using vi = vector<int>; using vb = vector<bool>; using vl = vector<ll>; using vd = vector<db>; using vs = vector<str>; using vpi = vector<pi>; using vpl = vector<pl>; using vpd = vector<pd>; #define tcT template<class T #define tcTU tcT, class U // ^ lol this makes everything look weird but I'll try it tcT> using V = vector<T>; tcT, size_t SZ> using AR = array<T,SZ>; tcT> using PR = pair<T,T>; // pairs #define mp make_pair #define f first #define s second // vectors // oops size(x), rbegin(x), rend(x) need C++17 #define sz(x) int((x).size()) #define bg(x) begin(x) #define all(x) bg(x), end(x) #define rall(x) x.rbegin(), x.rend() #define sor(x) sort(all(x)) #define rsz resize #define ins insert #define ft front() #define bk back() #define pb push_back #define eb emplace_back #define pf push_front #define rtn return #define lb lower_bound #define ub upper_bound tcT> int lwb(V<T>& a, const T& b) { return int(lb(all(a),b)-bg(a)); } // loops #define FOR(i,a,b) for (int i = (a); i < (b); ++i) #define F0R(i,a) FOR(i,0,a) #define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i) #define R0F(i,a) ROF(i,0,a) #define rep(a) F0R(_,a) #define each(a,x) for (auto& a: x) const int MOD = 1e9+7; // 998244353; const int MX = 2e5+5; const ll INF = 1e18; // not too close to LLONG_MAX const db PI = acos((db)-1); const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}; // for every grid problem!! mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()); template<class T> using pqg = priority_queue<T,vector<T>,greater<T>>; // bitwise ops // also see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html constexpr int pct(int x) { return __builtin_popcount(x); } // # of bits set constexpr int bits(int x) { // assert(x >= 0); // make C++11 compatible until USACO updates ... return x == 0 ? 0 : 31-__builtin_clz(x); } // floor(log2(x)) constexpr int p2(int x) { return 1<<x; } constexpr int msk2(int x) { return p2(x)-1; } ll cdiv(ll a, ll b) { return a/b+((a^b)>0&&a%b); } // divide a by b rounded up ll fdiv(ll a, ll b) { return a/b-((a^b)<0&&a%b); } // divide a by b rounded down tcT> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; } // set a = min(a,b) tcT> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; } tcTU> T fstTrue(T lo, T hi, U f) { hi ++; assert(lo <= hi); // assuming f is increasing while (lo < hi) { // find first index such that f is true T mid = lo+(hi-lo)/2; f(mid) ? hi = mid : lo = mid+1; } return lo; } tcTU> T lstTrue(T lo, T hi, U f) { lo --; assert(lo <= hi); // assuming f is decreasing while (lo < hi) { // find first index such that f is true T mid = lo+(hi-lo+1)/2; f(mid) ? lo = mid : hi = mid-1; } return lo; } tcT> void remDup(vector<T>& v) { // sort and remove duplicates sort(all(v)); v.erase(unique(all(v)),end(v)); } tcTU> void erase(T& t, const U& u) { // don't erase auto it = t.find(u); assert(it != end(t)); t.erase(it); } // element that doesn't exist from (multi)set // INPUT #define tcTUU tcT, class ...U tcT> void re(complex<T>& c); tcTU> void re(pair<T,U>& p); tcT> void re(V<T>& v); tcT, size_t SZ> void re(AR<T,SZ>& a); tcT> void re(T& x) { cin >> x; } void re(double& d) { str t; re(t); d = stod(t); } void re(long double& d) { str t; re(t); d = stold(t); } tcTUU> void re(T& t, U&... u) { re(t); re(u...); } tcT> void re(complex<T>& c) { T a,b; re(a,b); c = {a,b}; } tcTU> void re(pair<T,U>& p) { re(p.f,p.s); } tcT> void re(V<T>& x) { each(a,x) re(a); } tcT, size_t SZ> void re(AR<T,SZ>& x) { each(a,x) re(a); } tcT> void rv(int n, V<T>& x) { x.rsz(n); re(x); } // TO_STRING #define ts to_string str ts(char c) { return str(1,c); } str ts(const char* s) { return (str)s; } str ts(str s) { return s; } str ts(bool b) { // #ifdef LOCAL // return b ? "true" : "false"; // #else return ts((int)b); // #endif } tcT> str ts(complex<T> c) { stringstream ss; ss << c; return ss.str(); } str ts(V<bool> v) { str res = "{"; F0R(i,sz(v)) res += char('0'+v[i]); res += "}"; return res; } template<size_t SZ> str ts(bitset<SZ> b) { str res = ""; F0R(i,SZ) res += char('0'+b[i]); return res; } tcTU> str ts(pair<T,U> p); tcT> str ts(T v) { // containers with begin(), end() #ifdef LOCAL bool fst = 1; str res = "{"; for (const auto& x: v) { if (!fst) res += ", "; fst = 0; res += ts(x); } res += "}"; return res; #else bool fst = 1; str res = ""; for (const auto& x: v) { if (!fst) res += " "; fst = 0; res += ts(x); } return res; #endif } tcTU> str ts(pair<T,U> p) { #ifdef LOCAL return "("+ts(p.f)+", "+ts(p.s)+")"; #else return ts(p.f)+" "+ts(p.s); #endif } // OUTPUT tcT> void pr(T x) { cout << ts(x); } tcTUU> void pr(const T& t, const U&... u) { pr(t); pr(u...); } void ps() { pr("\n"); } // print w/ spaces tcTUU> void ps(const T& t, const U&... u) { pr(t); if (sizeof...(u)) pr(" "); ps(u...); } // DEBUG void DBG() { cerr << "]" << endl; } tcTUU> void DBG(const T& t, const U&... u) { cerr << ts(t); if (sizeof...(u)) cerr << ", "; DBG(u...); } #ifdef LOCAL // compile with -DLOCAL, chk -> fake assert #define dbg(...) cerr << "Line(" << __LINE__ << ") -> [" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__) #define chk(...) if (!(__VA_ARGS__)) cerr << "Line(" << __LINE__ << ") -> function(" \ << __FUNCTION__ << ") -> CHK FAILED: (" << #__VA_ARGS__ << ")" << "\n", exit(0); #else #define dbg(...) 0 #define chk(...) 0 #endif void setPrec() { cout << fixed << setprecision(15); } void unsyncIO() { cin.tie(0)->sync_with_stdio(0); } // FILE I/O void setIn(str s) { freopen(s.c_str(),"r",stdin); } void setOut(str s) { freopen(s.c_str(),"w",stdout); } void setIO(str s = "") { unsyncIO(); setPrec(); // cin.exceptions(cin.failbit); // throws exception when do smth illegal // ex. try to read letter into int if (sz(s)) setIn(s+".in"), setOut(s+".out"); // for USACO } #define ints(...); int __VA_ARGS__; re(__VA_ARGS__); int N,M; vi adj[MX]; V<AR<int,2>> gen_dist() { V<AR<int,2>> dist(N,{MOD,MOD}); queue<pi> q; auto ad = [&](int a, int b) { if (dist[a][b%2] != MOD) return; dist[a][b%2] = b; q.push({a,b}); }; ad(0,0); while (sz(q)) { pi p = q.ft; q.pop(); each(t,adj[p.f]) ad(t,p.s+1); } return dist; } int ans = 0; set<pi> distinct; int div2(int x) { return (x+1)/2; } void solve_between(vi nums, vb exists, bool special) { vi dp{0}; int res = MOD; F0R(i,sz(nums)) { if (i == sz(nums)-1) { if (special) { F0R(j,sz(dp)) F0R(k,nums[i]+1) { int need_one = max(nums[i]-min(j,2*k),0); if (!exists[i] && need_one) continue; ckmin(res,dp[j]+need_one+k); } } else { assert(exists[i]); each(t,dp) ckmin(res,t+nums[i]); } } else { vi DP(max(nums[i],nums[i+1])+1,MOD); F0R(j,sz(dp)) F0R(k,max(nums[i],nums[i+1])+1) { int need_one = max(nums[i]-min(j,k),0); if (!exists[i] && need_one) continue; ckmin(DP[k],dp[j]+need_one+k); } swap(dp,DP); } } ans += res; } void solve_sum(int sum, vpi v) { dbg("SOLVE SUM",sum,v); assert(sz(v)); if (v[0].f == 0) { F0R(i,sz(v)-1) ans += max(v[i].s,v[i+1].s); ans += div2(v.bk.s); return; } for (int i = 0; i < sz(v); ++i) { vi nums{v[i].s}; vb exists{distinct.count({v[i].f-1,sum-v[i].f-1})}; while (i+1 < sz(v) && v[i+1].f == v[i].f+1) { ++i; nums.pb(v[i].s); exists.pb(distinct.count({v[i].f-1,sum-v[i].f-1})); } bool special = 0; if (2*v[i].f+1 == sum) special = 1; solve_between(nums,exists,special); } } void go() { auto a = gen_dist(); if (a[0][1] == MOD) { ps(N-1); return; } map<int,map<int,int>> cnt; each(t,a) { pi p{t[0],t[1]}; if (p.f > p.s) swap(p.f,p.s); distinct.ins(p); ++cnt[p.f+p.s][p.f]; } each(t,cnt) solve_sum(t.f,vpi(all(t.s))); ps(ans); } int main() { setIO(); int T; re(T); F0R(_,T) { re(N,M); F0R(i,N) adj[i].clear(); ans = 0; distinct.clear(); F0R(i,M) { int a,b; re(a,b); --a,--b; adj[a].pb(b), adj[b].pb(a); } go(); } } /* stuff you should look for * int overflow, array bounds * special cases (n=1?) * do smth instead of nothing and stay organized * WRITE STUFF DOWN * DON'T GET STUCK ON ONE APPROACH */
Approach 2: For full credit, we can assign edges greedily.
Suppose that we have already added edges from to in order to satisfy the conditions for vertices . Let's assign each of these edges to different vertices if possible, meaning that we have at least vertices with edges to .
Danny's code (which doesn't explicitly group vertices by ):
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; public class MinimizingEdgesActuallyCorrect { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer tokenizer = new StringTokenizer(in.readLine()); int n = Integer.parseInt(tokenizer.nextToken()); int m = Integer.parseInt(tokenizer.nextToken()); List<Integer>[] adj = new List[(2 * n) + 1]; for (int a = 1; a <= 2 * n; a++) { adj[a] = new ArrayList<>(); } for (int j = 1; j <= m; j++) { tokenizer = new StringTokenizer(in.readLine()); int a = Integer.parseInt(tokenizer.nextToken()); int b = Integer.parseInt(tokenizer.nextToken()); adj[a].add(b + n); adj[b + n].add(a); adj[a + n].add(b); adj[b].add(a + n); } int[] dist = new int[(2 * n) + 1]; Arrays.fill(dist, -1); dist[1] = 0; LinkedList<Integer> q = new LinkedList<>(); q.add(1); while (!q.isEmpty()) { int a = q.remove(); for (int b : adj[a]) { if (dist[b] == -1) { dist[b] = dist[a] + 1; q.add(b); } } } int answer = 0; if (dist[n + 1] == -1) { answer = n - 1; } else { TreeMap<Pair, Integer> freq = new TreeMap<>(); TreeMap<Pair, List<Integer>> buckets = new TreeMap<>(); for (int a = 1; a <= n; a++) { freq.merge(new Pair(Math.min(dist[a], dist[n + a]), Math.max(dist[a], dist[n + a])), 1, Integer::sum); buckets.computeIfAbsent(new Pair(Math.min(dist[a], dist[n + a]), Math.max(dist[a], dist[n + a])), __ -> new ArrayList<>()).add(a); } TreeMap<Pair, Integer> edgeAmt = new TreeMap<>(); for (Map.Entry<Pair, Integer> entry : freq.entrySet()) { Pair p = entry.getKey(); int f = entry.getValue(); int prev = edgeAmt.getOrDefault(new Pair(p.first - 1, p.second + 1), 0); if (p.second == p.first + 1) { if (p.first == 0) { answer += (f + 1) / 2; } else if (freq.containsKey(new Pair(p.first - 1, p.second - 1))) { answer += Math.max((f - prev) + ((prev + 1) / 2), (f + 1) / 2); } else { if (prev < f) { answer += f - prev; } answer += (f + 1) / 2; } } else { answer += f; if (p.first == 0) { edgeAmt.put(p, f); } else if (freq.containsKey(new Pair(p.first - 1, p.second - 1))) { edgeAmt.put(p, Math.min(f, prev)); } else { if (prev < f) { answer += f - prev; } edgeAmt.put(p, f); } } } } System.out.println(answer); } static class Pair implements Comparable<Pair> { final int first; final int second; Pair(int first, int second) { this.first = first; this.second = second; } @Override public int compareTo(Pair other) { if (first != other.first) { return first - other.first; } else { return second - other.second; } } } }
My code (which constructs a solution):
#include <bits/stdc++.h> using namespace std; using ll = long long; using db = long double; // or double, if TL is tight using str = string; // yay python! using pi = pair<int,int>; using pl = pair<ll,ll>; using pd = pair<db,db>; using vi = vector<int>; using vb = vector<bool>; using vl = vector<ll>; using vd = vector<db>; using vs = vector<str>; using vpi = vector<pi>; using vpl = vector<pl>; using vpd = vector<pd>; #define tcT template<class T #define tcTU tcT, class U // ^ lol this makes everything look weird but I'll try it tcT> using V = vector<T>; tcT, size_t SZ> using AR = array<T,SZ>; tcT> using PR = pair<T,T>; // pairs #define mp make_pair #define f first #define s second // vectors // oops size(x), rbegin(x), rend(x) need C++17 #define sz(x) int((x).size()) #define bg(x) begin(x) #define all(x) bg(x), end(x) #define rall(x) x.rbegin(), x.rend() #define sor(x) sort(all(x)) #define rsz resize #define ins insert #define ft front() #define bk back() #define pb push_back #define eb emplace_back #define pf push_front #define rtn return #define lb lower_bound #define ub upper_bound tcT> int lwb(V<T>& a, const T& b) { return int(lb(all(a),b)-bg(a)); } // loops #define FOR(i,a,b) for (int i = (a); i < (b); ++i) #define F0R(i,a) FOR(i,0,a) #define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i) #define R0F(i,a) ROF(i,0,a) #define rep(a) F0R(_,a) #define each(a,x) for (auto& a: x) const int MOD = 1e9+7; // 998244353; const int MX = 2e5+5; const ll INF = 1e18; // not too close to LLONG_MAX const db PI = acos((db)-1); const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}; // for every grid problem!! mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()); template<class T> using pqg = priority_queue<T,vector<T>,greater<T>>; // bitwise ops // also see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html constexpr int pct(int x) { return __builtin_popcount(x); } // # of bits set constexpr int bits(int x) { // assert(x >= 0); // make C++11 compatible until USACO updates ... return x == 0 ? 0 : 31-__builtin_clz(x); } // floor(log2(x)) constexpr int p2(int x) { return 1<<x; } constexpr int msk2(int x) { return p2(x)-1; } ll cdiv(ll a, ll b) { return a/b+((a^b)>0&&a%b); } // divide a by b rounded up ll fdiv(ll a, ll b) { return a/b-((a^b)<0&&a%b); } // divide a by b rounded down tcT> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; } // set a = min(a,b) tcT> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; } tcTU> T fstTrue(T lo, T hi, U f) { hi ++; assert(lo <= hi); // assuming f is increasing while (lo < hi) { // find first index such that f is true T mid = lo+(hi-lo)/2; f(mid) ? hi = mid : lo = mid+1; } return lo; } tcTU> T lstTrue(T lo, T hi, U f) { lo --; assert(lo <= hi); // assuming f is decreasing while (lo < hi) { // find first index such that f is true T mid = lo+(hi-lo+1)/2; f(mid) ? lo = mid : hi = mid-1; } return lo; } tcT> void remDup(vector<T>& v) { // sort and remove duplicates sort(all(v)); v.erase(unique(all(v)),end(v)); } tcTU> void erase(T& t, const U& u) { // don't erase auto it = t.find(u); assert(it != end(t)); t.erase(it); } // element that doesn't exist from (multi)set // INPUT #define tcTUU tcT, class ...U tcT> void re(complex<T>& c); tcTU> void re(pair<T,U>& p); tcT> void re(V<T>& v); tcT, size_t SZ> void re(AR<T,SZ>& a); tcT> void re(T& x) { cin >> x; } void re(double& d) { str t; re(t); d = stod(t); } void re(long double& d) { str t; re(t); d = stold(t); } tcTUU> void re(T& t, U&... u) { re(t); re(u...); } tcT> void re(complex<T>& c) { T a,b; re(a,b); c = {a,b}; } tcTU> void re(pair<T,U>& p) { re(p.f,p.s); } tcT> void re(V<T>& x) { each(a,x) re(a); } tcT, size_t SZ> void re(AR<T,SZ>& x) { each(a,x) re(a); } tcT> void rv(int n, V<T>& x) { x.rsz(n); re(x); } // TO_STRING #define ts to_string str ts(char c) { return str(1,c); } str ts(const char* s) { return (str)s; } str ts(str s) { return s; } str ts(bool b) { // #ifdef LOCAL // return b ? "true" : "false"; // #else return ts((int)b); // #endif } tcT> str ts(complex<T> c) { stringstream ss; ss << c; return ss.str(); } str ts(V<bool> v) { str res = "{"; F0R(i,sz(v)) res += char('0'+v[i]); res += "}"; return res; } template<size_t SZ> str ts(bitset<SZ> b) { str res = ""; F0R(i,SZ) res += char('0'+b[i]); return res; } tcTU> str ts(pair<T,U> p); tcT> str ts(T v) { // containers with begin(), end() #ifdef LOCAL bool fst = 1; str res = "{"; for (const auto& x: v) { if (!fst) res += ", "; fst = 0; res += ts(x); } res += "}"; return res; #else bool fst = 1; str res = ""; for (const auto& x: v) { if (!fst) res += " "; fst = 0; res += ts(x); } return res; #endif } tcTU> str ts(pair<T,U> p) { #ifdef LOCAL return "("+ts(p.f)+", "+ts(p.s)+")"; #else return ts(p.f)+" "+ts(p.s); #endif } // OUTPUT tcT> void pr(T x) { cout << ts(x); } tcTUU> void pr(const T& t, const U&... u) { pr(t); pr(u...); } void ps() { pr("\n"); } // print w/ spaces tcTUU> void ps(const T& t, const U&... u) { pr(t); if (sizeof...(u)) pr(" "); ps(u...); } // DEBUG void DBG() { cerr << "]" << endl; } tcTUU> void DBG(const T& t, const U&... u) { cerr << ts(t); if (sizeof...(u)) cerr << ", "; DBG(u...); } #ifdef LOCAL // compile with -DLOCAL, chk -> fake assert #define dbg(...) cerr << "Line(" << __LINE__ << ") -> [" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__) #define chk(...) if (!(__VA_ARGS__)) cerr << "Line(" << __LINE__ << ") -> function(" \ << __FUNCTION__ << ") -> CHK FAILED: (" << #__VA_ARGS__ << ")" << "\n", exit(0); #else #define dbg(...) 0 #define chk(...) 0 #endif void setPrec() { cout << fixed << setprecision(15); } void unsyncIO() { cin.tie(0)->sync_with_stdio(0); } // FILE I/O void setIn(str s) { freopen(s.c_str(),"r",stdin); } void setOut(str s) { freopen(s.c_str(),"w",stdout); } void setIO(str s = "") { unsyncIO(); setPrec(); // cin.exceptions(cin.failbit); // throws exception when do smth illegal // ex. try to read letter into int if (sz(s)) setIn(s+".in"), setOut(s+".out"); // for USACO } #define ints(...); int __VA_ARGS__; re(__VA_ARGS__); int N,M; vi adj[MX]; V<AR<int,2>> gen_dist() { V<AR<int,2>> dist(N,{MOD,MOD}); queue<pi> q; auto ad = [&](int a, int b) { if (dist[a][b%2] != MOD) return; dist[a][b%2] = b; q.push({a,b}); }; ad(0,0); while (sz(q)) { pi p = q.ft; q.pop(); each(t,adj[p.f]) ad(t,p.s+1); } return dist; } vpi ans_ed; map<pi,int> distinct; vpi group; int div2(int x) { return (x+1)/2; } void satisfy(vi a, vi b) { F0R(i,max(sz(a),sz(b))) ans_ed.pb({a[min(i,sz(a)-1)],b[min(i,sz(b)-1)]}); } void satisfy_self(vi a) { for (int i = 0; i < sz(a); i += 2) { if (i == sz(a)-1) ans_ed.pb({a[i],a[i]}); else ans_ed.pb({a[i],a[i+1]}); } } void satisfy_lower_left(vi v) { each(t,v) { pi p = group[t]; --p.f,--p.s; assert(distinct.count(p)); ans_ed.pb({t,distinct[p]}); } } void satisfy_upper_left(vi v) { each(t,v) { pi p = group[t]; --p.f,++p.s; assert(distinct.count(p)); ans_ed.pb({t,distinct[p]}); } } void solve_between(V<vi> nums, vb exists, bool special) { vi bef; F0R(i,sz(nums)) { vi yes = nums[i], no; while (sz(yes) > sz(bef)) { no.pb(yes.bk); yes.pop_back(); } satisfy(bef,yes); if (i == sz(nums)-1) { if (special) { // ans += nums[i]-sz(bef); if (exists[i]) { satisfy_lower_left(no); // for each in yes: loop // for each in no: go to // ans += div2(bef); satisfy_self(yes); } else { satisfy_upper_left(no); satisfy_self(nums[i]); } } else { assert(exists[i]); satisfy_lower_left(nums[i]); } } else if (exists[i]) { bef = yes; satisfy_lower_left(no); } else { satisfy_upper_left(no); bef = nums[i]; } } } void solve_sum(int sum, V<pair<int,vi>> v) { dbg("SOLVE SUM",sum,v); assert(sz(v)); if (v[0].f == 0) { F0R(i,sz(v)-1) satisfy(v[i].s,v[i+1].s); satisfy_self(v.bk.s); return; } for (int i = 0; i < sz(v); ++i) { V<vi> nums{v[i].s}; vb exists{distinct.count({v[i].f-1,sum-v[i].f-1})}; while (i+1 < sz(v) && v[i+1].f == v[i].f+1) { ++i; nums.pb(v[i].s); exists.pb(distinct.count({v[i].f-1,sum-v[i].f-1})); } bool special = 0; if (2*v[i].f+1 == sum) special = 1; solve_between(nums,exists,special); } } void solve() { auto a = gen_dist(); // dbg(a); if (a[0][1] == MOD) { ps(N-1); return; } map<int,map<int,vi>> cnt; F0R(i,N) { AR<int,2> t = a[i]; pi p{t[0],t[1]}; if (p.f > p.s) swap(p.f,p.s); group.pb(p); distinct[p] = i; cnt[p.f+p.s][p.f].pb(i); } each(t,cnt) solve_sum(t.f,V<pair<int,vi>>(all(t.s))); F0R(i,N) adj[i].clear(); each(t,ans_ed) adj[t.f].pb(t.s), adj[t.s].pb(t.f); assert(a == gen_dist()); ps(sz(ans_ed)); assert(sz(ans_ed) <= M); } int main() { setIO(); int TC; re(TC); F0R(_,TC) { re(N,M); distinct.clear(); F0R(i,N) adj[i].clear(); ans_ed.clear(); group.clear(); F0R(i,M) { int a,b; re(a,b); --a,--b; adj[a].pb(b), adj[b].pb(a); } solve(); } }