Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
// #define endl '\n'
#define int long long int
#define rep(i, a, b) for (int i = a; i < b; i++)
#define revrep(i, a, b) for (int i = a; i >= b; i--)
#define pb push_back
#define pii pair<int, int>
#define vi vector<int>
#define vii vector<pii>
#define min3(a, b, c) min(a, min(b, c))
#define max3(a, b, c) max(a, max(b, c))
#define upb(vec, val) upper_bound((vec).begin(), (vec).end(), (val)) - (vec).begin()
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T>
using ordered_multiset = tree<T, null_type, less_equal<T>, rb_tree_tag, tree_order_statistics_node_update>;
ostream &operator<<( ostream &output, const pii &p ) { output << p.first << " " << p.second;return output; }
istream &operator>>( istream &input, pii &p ) { input >> p.first >> p.second;return input; }
template<typename T>
void inline println(vector<T> args){ for(T i: args)cout<<i<<" ";cout<<endl; }
void amax(int& a, int b) { a = max(a, b); }
void amin(int& a, int b) { a = min(a, b); }
int ceilInt(int a, int b) {
if(!b) return 0;
if(a%b) return a/b + 1;
return a/b;
}
int INF = 1e18;
int MOD = 1e9+7;
vector<vi> adj, parent;
vi h, depth;
vii order, inout;
int n, t;
void dfs(int v, int p) {
inout[v].first = t++;
parent[v][0] = p;
depth[v] = 0;
for(int i: adj[v]) {
if(i == p) continue;
h[i] = h[v]+1;
dfs(i, v);
amax(depth[v], depth[i]+1);
}
sort(adj[v].rbegin(), adj[v].rend(), [&](int i, int j) {
return depth[i] < depth[j];
});
inout[v].second = t++;
}
void processParent() {
rep(j, 1, 20) {
rep(i, 0, n) {
int p = parent[i][j-1];
if(p != -1)
parent[i][j] = parent[p][j-1];
else
parent[i][j] = p;
}
}
}
bool isAncestor(int p, int v) {
return inout[p].first <= inout[v].first && inout[v].second <= inout[p].second;
}
int findLCA(int a, int b) {
if(isAncestor(a, b)) return a;
if(isAncestor(b, a)) return b;
for(int i=19; i>=0; i--) {
int p = parent[a][i];
if(p != -1 && !isAncestor(p, b))
a = p;
}
return parent[a][0];
}
void findOrder(int v, int p) {
for(int i: adj[v]) {
if(i == p) continue;
findOrder(i, v);
}
if(adj[v].size() == 1 && p != -1) {
int lst = order.back().second;
int lca = findLCA(v, lst);
int pathLen = abs(h[lca]-h[v]);
order.pb({pathLen, v});
}
}
int diameterDfs() {
dfs(0, -1);
int mx = *max_element(h.begin(), h.end());
rep(i, 0, n) {
if(h[i] == mx) {
return i;
}
}
return -1;
}
void solve()
{
int k; cin>>n>>k;
t = 0;
inout.clear(), inout.resize(n);
adj.clear(), adj.resize(n);
h.clear(), h.resize(n, 0);
depth.clear(), depth.resize(n, 0);
parent.clear(), parent.resize(n, vi(20, 0));
order.clear();
rep(i, 0, n-1) {
int a, b; cin>>a>>b;
a--, b--;
adj[a].pb(b);
adj[b].pb(a);
}
int root = diameterDfs();
h.assign(n, 0);
depth.assign(n, 0);
order.pb({1, root});
t = 0;
dfs(root, -1);
processParent();
findOrder(root, -1);
int ans = 1; k--;
order.erase(order.begin());
sort(order.rbegin(), order.rend());
rep(i, 0, n) {
if(k <= 0) break;
k -= order[i].first;
ans++;
}
cout<<ans<<endl;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
// for getting input from input.txt
freopen("input.txt", "r", stdin);
// for writing output to output.txt
freopen("output.txt", "w", stdout);
#endif
int t = 1;
cin>>t;
rep(i, 0, t)
{
// cout<<"Case #"<<i+1<<": ";
solve();
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vector<int>>
int getFAaaar(int node, vvi & G, int n){
vector<bool> done(n+1, false);
int Faadu=-1, far; done[node] = true;
queue<pair<int, int>> qu; qu.push({node, 0});
while(qu.size()){
auto pi = qu.front(); qu.pop();
int nod = pi.first, dis = pi.second;
if(Faadu < dis) Faadu = dis, far = nod;
for(auto cnod: G[nod]){
if(done[cnod]) continue;
done[cnod] = true;
qu.push({cnod, dis+1});
}
}
return far;
}
void dfs(int nod, int par, vvi & G, vi & H, vi & li, int cur){
bool kiyaleafHai = true;
int mx = 0;
for(auto cnod: G[nod]) if(cnod != par) {kiyaleafHai = false; mx = max(mx, H[cnod]);}
if(kiyaleafHai){ li.push_back(cur); return; }
int c = 0;
for(auto cnod: G[nod]){
if(cnod == par) continue;
if(H[cnod] == mx && c==0){
dfs(cnod, nod, G, H, li, cur+1); c++;
}
else dfs(cnod, nod, G, H, li, 1);
}
}
void fixHeight(int nod, int par, vvi & G, vi & H){
bool kiyaleafHai = true;
for(auto cnod: G[nod]){
if(cnod == par) continue;
kiyaleafHai = false;
fixHeight(cnod, nod, G, H);
H[nod] = max(H[nod], 1 + H[cnod]);
}
if(kiyaleafHai) H[nod] = 1;
}
void breakIntoLines(int nod, int par, vvi & G, vi&li, int n){
vector<int> H(n+1, 0);
fixHeight(nod, par, G, H);
dfs(nod, par, G, H, li, 1);
}
int solutionNikal(vvi & gr, int n, int k){
if(k==1) return 1;
int u = getFAaaar(1, gr, n);
vector<int> li;
breakIntoLines(u, 0, gr, li, n);
sort(li.rbegin(), li.rend());
int size = 1, total = 0, i = 0;
while(total < k){
size++; total += li[i++];
}
return size;
}
void solve(){
int n, k;
int u, v;
cin>>n>>k;
vvi gr(n+1);
for(int i=1; i<n; i++){
cin>>u>>v;
gr[u].push_back(v); gr[v].push_back(u);
}
cout << solutionNikal(gr, n, k) << "\n";
}
int32_t main(){
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int t;
cin>>t;
// t = 1;
int _=1;
while(t--){
// cout<<"Case #"<<_++<<": ";
solve();
}
return 0;
}
"""
Url: https://www.codechef.com/problems/SUBTRCOV
"""
__author__ = "Ronald Kaiser"
__email__ = "raios dot catodicos at gmail dot com"
from sys import stdin, stdout
WHITE = 0
GRAY = 1
BLACK = 2
read_numbers = lambda: list(map(int, stdin.readline().strip().split()))
output_line = lambda x: stdout.write(x)
def find_farthest_leaf(N, E, root=0):
color = [WHITE] * N
farthest_leaf = root
level = 0
max_level = 0
color[root] = GRAY
stack = [root]
while stack:
cur = stack[-1]
if color[cur] == BLACK:
stack.pop()
level -= 1
continue
level += 1
if level >= max_level:
max_level = level
farthest_leaf = cur
for child in E[cur]:
if color[child] == BLACK:
continue
if color[child] == WHITE:
color[child] = GRAY
stack.append(child)
color[cur] = BLACK
return farthest_leaf
def search_strips(N, E, root):
color = [WHITE] * N
strips = [[] for _ in range(N)]
children = [[] for _ in range(N)]
leafs = [False] * N
color[root] = GRAY
stack = [root]
while stack:
cur = stack[-1]
if color[cur] == BLACK:
"""
When all children of "cur" node are processed
and it is ready to get out of the stack we can
calculate the strips it contributes to the
tree until this point, so it can be collected by its
parent later, like a DFS in a recursive approach
saving its returning value to be used by the caller.
"""
stack.pop()
new_strips = []
for child in children[cur]:
if leafs[child]:
new_strips += [1]
else:
if len(strips[child]):
strips[child][0] += 1
new_strips += strips[child]
new_strips.sort(reverse=True)
strips[cur] = new_strips
continue
for child in E[cur]:
if color[child] == BLACK:
continue
if color[child] == WHITE:
color[child] = GRAY
stack.append(child)
children[cur].append(child)
leafs[cur] = False if children[cur] else True
color[cur] = BLACK
return strips[root]
def solve(N, E, k):
if k == 1: return 1
if k == 2: return 2
farthest_leaf = find_farthest_leaf(N, E)
strips = search_strips(N, E, root=farthest_leaf)
max_k = 1
solution = 1
for strip in strips:
max_k += strip
solution += 1
if k <= max_k:
return solution
def main():
solutions = []
for _ in range(int(input())):
n, k = read_numbers()
E = [[] for _ in range(n)]
for _ in range(n - 1):
u, v = read_numbers()
u -= 1
v -= 1
E[u].append(v)
E[v].append(u)
solution = solve(n, E, k)
solutions.append(str(solution))
solutions = '\n'.join(solutions)
output_line(solutions)
main()
#include <stdio.h>
#include<stdlib.h>
int comp(const void *p, const void *q)
{
return *(int*)q - *(int*)p;
}
typedef struct
{
int deg, depth, val;
int* c;
} adj;
int bfs(adj node[], int n, int p)
{
int i, q[n], front=0, rear=0, visited[n+1];
for(i=1; i<=n; i++) visited[i] = 0;
q[front++] = p;
while(front!=rear)
{
p = q[rear++];
visited[p] = 1;
for(i=0; i<node[p].deg; i++)
if(!visited[node[p].c[i]]) q[front++] = node[p].c[i];
}
return p;
}
int assigndepth(adj node[], int n, int p, int parent)
{
if(node[p].deg==1) return node[p].depth = 1;
node[p].depth = 0;
for(int i=0, v; i<node[p].deg; i++)
{
if(node[p].c[i]==parent) continue;
v = assigndepth(node, n, node[p].c[i], p);
if(node[p].depth<v) node[p].depth = v;
}
return ++node[p].depth;
}
void assignval(adj node[], int n, int p, int parent, int val)
{
int i, lc=0, lv=0; //child of longest path and length of that
node[p].val = val;
for(i=0; i<node[p].deg; i++) //find lc, lv
{
if(node[p].c[i]==parent) continue;
if(lv<node[node[p].c[i]].depth) lv=node[node[p].c[lc=i]].depth;
}
for(i=0; i<node[p].deg; i++)
{
if(node[p].c[i]==parent) continue;
if(i==lc) assignval(node, n, node[p].c[i], p, val+1);
else assignval(node, n, node[p].c[i], p, 1);
}
}
int main(void)
{
int T;
scanf("%d", &T);
while(T--)
{
int n, k, i, l=0;
scanf("%d %d", &n, &k);
int e[n-1][2], p[n+1], leafval[n];
adj node[n+1];
for(i=1; i<=n; i++) node[i].deg=0;
for(i=0; i<n-1; i++)
{
scanf("%d %d", &e[i][0], &e[i][1]);
node[e[i][0]].deg++; node[e[i][1]].deg++;
}
if(k==1)
{
printf("1\n");
continue;
}
for(i=1; i<=n; i++)
{
node[i].c = (int*)malloc(node[i].deg*sizeof(int));
p[i] = 0;
}
for(i=0; i<n-1; i++)
{
node[e[i][0]].c[p[e[i][0]]++] = e[i][1];
node[e[i][1]].c[p[e[i][1]]++] = e[i][0];
}
int src = bfs(node, n, 1);
node[src].depth = assigndepth(node, n, node[src].c[0], src)+1;
//for(i=1; i<=n; i++) printf("%d %d\n",i,node[i].depth);
node[src].val=0;
assignval(node, n, node[src].c[0], src, 2);
//for(i=1; i<=n; i++) printf("%d %d\n",i,node[i].val);
for(i=1; i<=n; i++) if(node[i].deg==1) leafval[l++] = node[i].val;
qsort(leafval, l, sizeof(int), comp);
for(i=0; k>0; i++) k -= leafval[i];
printf("%d\n", i+1);
}
return 0;
}
import java.util.*;
import java.io.*;
class SUBTRCOV{
//SOLUTION BEGIN
void pre() throws Exception{}
void solve(int TC) throws Exception{
int N = ni(), K = ni();
int[] from = new int[N-1], to = new int[N-1];
for(int i = 0; i< N-1; i++){
from[i] = ni()-1;
to[i] = ni()-1;
}
int[][] g = make(N, from, to);
int root = 0;
int[] dist = new int[N];Arrays.fill(dist, 2*N);
dist[0] = 0;
Queue<Integer> q = new LinkedList<>();
q.add(0);
while(!q.isEmpty()){
int u = q.poll();
for(int v:g[u]){
if(dist[v] > dist[u]+1){
dist[v] = dist[u]+1;
q.add(v);
}
}
}
for(int i = 0; i< N; i++)if(dist[i] > dist[root])root = i;
time = -1;
int[] eu = new int[N], st = new int[N], en = new int[N], depth = new int[N], par = new int[N];
dfs(g, par, depth, eu, st, en, root, -1);
LazySegmentTree segmentTree = new LazySegmentTree(N);
for(int i = 0; i< N; i++)segmentTree.update(st[i], st[i], depth[i]);
boolean[] inc = new boolean[N];
inc[root] = true;
int size = 1, ans = 1;
long IINF = (long)1e13;
segmentTree.update(st[root], st[root], -IINF);
while(size < K){
long[] pair = segmentTree.query(0, N-1);
int u = eu[(int)pair[0]];
int add = (int)pair[1];
ans++;
for(int cur = u; !inc[cur]; cur = par[cur]){
size++;
segmentTree.update(st[cur], st[cur], -IINF);
inc[cur] = true;
for(int v:g[cur]){
if(v == par[cur] || inc[v])continue;
segmentTree.update(st[v], en[v], -add);
}
add--;
}
}
pn(ans);
}
int time;
void dfs(int[][] g, int[] par, int[] depth, int[] eu, int[] st, int[] en, int u, int p){
par[u] = p;
eu[++time] = u;
st[u] = time;
for(int v:g[u]){
if(v == p)continue;
depth[v] = depth[u]+1;
dfs(g, par, depth, eu, st, en, v, u);
}
en[u] = time;
}
class LazySegmentTree{
int m = 1;
long IINF = (long)1e18;
long[] t, lazy;
long[] ind;
public LazySegmentTree(int n){
while(m<n)m<<=1;
t = new long[m<<1];
lazy = new long[m<<1];
ind = new long[m<<1];
for(int i = 0; i< m; i++)ind[m+i] = i;
for(int i = m-1; i> 0; i--)
ind[i] = t[i<<1] <= t[i<<1|1]?ind[i<<1]:ind[i<<1|1];
}
private void push(int i, int ll, int rr){
if(lazy[i] != 0){
t[i] += lazy[i];
if(i < m){
lazy[i<<1] += lazy[i];
lazy[i<<1|1] += lazy[i];
}
lazy[i] = 0;
}
}
public void update(int l, int r, long x){u(l, r, 0, m-1, 1, x);}
public long[] query(int l, int r){return q(l, r, 0, m-1, 1);}
public long max(int l, int r){return query(l, r)[1];}
public int argmax(int l, int r){return (int)query(l, r)[0];}
private void u(int l, int r, int ll, int rr, int i, long x){
push(i, ll, rr);
if(l == ll && r == rr){
lazy[i] += x;
push(i, ll, rr);return;
}
int mid = (ll+rr)/2;
if(r <= mid){
u(l, r, ll, mid, i<<1, x);
push(i<<1|1, mid+1, rr);
}else if(l > mid){
push(i<<1, ll, mid);
u(l, r, mid+1, rr, i<<1|1, x);
}else{
u(l, mid, ll, mid, i<<1, x);
u(mid+1, r, mid+1, rr, i<<1|1, x);
}
t[i] = Math.max(t[i<<1], t[i<<1|1]);
if(t[i] == t[i<<1])ind[i] = ind[i<<1];
if(t[i] == t[i<<1|1])ind[i] = ind[i<<1|1];
}
private long[] q(int l, int r, int ll, int rr, int i){
if(l == ll && r == rr)return new long[]{ind[i], t[i]};
int mid = (ll+rr)>>1;
if(r <= mid)return q(l, r, ll, mid, i<<1);
if(l > mid)return q(l, r, mid+1, rr, i<<1|1);
long[] p1 = q(l, mid, ll, mid, i<<1), p2 = q(mid+1, r, mid+1, rr, i<<1|1);
if(p1[1] >= p2[1])return p1;
return p2;
}
}
int[][] make(int N, int[] from, int[] to){
int[] cnt = new int[N];
for(int x:from)cnt[x]++;
for(int x:to)cnt[x]++;
int[][] g = new int[N][];
for(int i = 0; i< N; i++)g[i] = new int[cnt[i]];
for(int i = 0; i< N-1; i++){
g[from[i]][--cnt[from[i]]] = to[i];
g[to[i]][--cnt[to[i]]] = from[i];
}
return g;
}
//SOLUTION END
void hold(boolean b)throws Exception{if(!b)throw new Exception("Hold right there, Sparky!");}
static boolean multipleTC = true;
FastReader in;PrintWriter out;
void run() throws Exception{
in = new FastReader();
out = new PrintWriter(System.out);
//Solution Credits: Taranpreet Singh
int T = (multipleTC)?ni():1;
pre();for(int t = 1; t<= T; t++)solve(t);
out.flush();
out.close();
}
public static void main(String[] args) throws Exception{
new SUBTRCOV().run();
}
int bit(long n){return (n==0)?0:(1+bit(n&(n-1)));}
void p(Object o){out.print(o);}
void pn(Object o){out.println(o);}
void pni(Object o){out.println(o);out.flush();}
String n()throws Exception{return in.next();}
String nln()throws Exception{return in.nextLine();}
int ni()throws Exception{return Integer.parseInt(in.next());}
long nl()throws Exception{return Long.parseLong(in.next());}
double nd()throws Exception{return Double.parseDouble(in.next());}
class FastReader{
BufferedReader br;
StringTokenizer st;
public FastReader(){
br = new BufferedReader(new InputStreamReader(System.in));
}
public FastReader(String s) throws Exception{
br = new BufferedReader(new FileReader(s));
}
String next() throws Exception{
while (st == null || !st.hasMoreElements()){
try{
st = new StringTokenizer(br.readLine());
}catch (IOException e){
throw new Exception(e.toString());
}
}
return st.nextToken();
}
String nextLine() throws Exception{
String str = "";
try{
str = br.readLine();
}catch (IOException e){
throw new Exception(e.toString());
}
return str;
}
}
}
import sys
from sys import path_hooks, stdin, stdout
sys.setrecursionlimit(11**(5))
from collections import deque,defaultdict,Counter
import heapq
for test in range(int(input())):
def solve():
n,k = map(int, stdin.readline().split())
adj = defaultdict(list)
for i in range(n-1):
u,v = map(int, stdin.readline().split())
u -= 1
v -= 1
adj[u].append(v)
adj[v].append(u)
if k < 4:
return min(2,k)
# method return farthest node and its distance from node u
def BFS(u):
visited = set()
distance = [-1 for i in range(n + 1)]
distance[u] = 0
queue = deque()
queue.append(u)
visited.add(u)
while queue:
front = queue.popleft()
for i in adj[front]:
if i not in visited:
visited.add(i)
distance[i] = distance[front]+1
queue.append(i)
maxDis = 0
for i in range(n):
if distance[i] > maxDis:
maxDis = distance[i]
node = i
return node
node = BFS(0)
depth = {}
visited = [False for i in range(n + 1)]
def bfs(u):
dd = 0
visited[u] = True
que = []
for i in adj[u]:
if visited[i] == False:
visited[i] = True
que.append(i)
for i in que:
dd = max(bfs(i) , dd)
depth[u] = 1 + dd
return 1 + dd
bfs(node)
exist = set()
visited = [False for i in range(n + 1)]
ele = node
while ele != -1 :
exist.add(ele)
visited[ele] = True
ma = 0
n1 = -1
for i in adj[ele]:
if visited[i] == False:
visited[i] = True
if depth[i] > ma:
ma = depth[i]
n1 = i
ele = n1
#print(exist)
exx = len(exist)
cc = Counter()
for i in depth:
if i not in exist:
cc[depth[i]] += 1
sor = sorted( list(cc.keys()) ,reverse= True)
pointer = 0
ans = 2
for i in sor:
tt = cc[i] - pointer
flag = False
for j in range(tt):
if exx >= k:
flag = True
break
exx += i
ans += 1
pointer += 1
if flag:
break
return ans
print(solve())
import sys
from random import randint
MOD = 10**9+7
sys.setrecursionlimit(MOD)
LOG_LEVEL = 0
def log(lvl, *args):
if lvl <= LOG_LEVEL:
msg = " ".join(map(str, args))
print >> sys.stderr, "log", lvl, ":", msg
class Node:
def __init__(self, num, parent):
self.num = num
self.parent = parent
self.weight = 1
def __repr__(self):
rep = "(" + str(self.num) + ", " + \
(str(self.parent) if type(self.parent) == int else str(self.parent.num)) + ", " + \
str(self.weight) + ")"
return rep
def build_graph(n, edges):
graph = [{} for _ in xrange(n+1)]
for u, v in edges:
graph[u][v] = None
graph[v][u] = None
return graph
def solve_brute(n, k, edges):
def dfs(edges, num, parent, height, visited, leaves=None):
visited[num] = True
node = Node(num, parent)
ans = (height, [])
neighbours = graph[num]
for c in neighbours:
if not visited[c]:
ret = dfs(edges, c, node, height+1, visited, leaves)
ans = max(ans, ret)
if leaves != None and ans[1] == []:
leaves.append(node)
ans[1].append(node)
return ans
log(1, "input:", edges, k)
if k < 3:
return k
dummy = Node(0, None)
graph = build_graph(n, edges)
visited = [False for i in xrange(n+1)]
ret = dfs(edges, 1, dummy, 0, visited)
leaves = []
visited = [False for i in xrange(n+1)]
ret = dfs(edges, ret[1][0].num, dummy, 0, visited, leaves)
log(1, leaves)
diamater = ret[1]
leaves.append(leaves[0])
leaves[0] = diamater[-1]
for i in xrange(2, len(leaves)):
if leaves[i] is diamater[0]:
leaves[1], leaves[i] = leaves[i], leaves[1]
break
s = set(diamater)
log(1, leaves)
ans = 2
while len(s) < k:
log(2, len(s), k)
max_arr = []
for i in xrange(ans, len(leaves)):
ptr = leaves[i]
arr = []
while ptr not in s:
arr.append(ptr)
ptr = ptr.parent
if len(arr) > len(max_arr):
max_arr = arr
leaves[ans], leaves[i] = leaves[i], leaves[ans]
s.update(max_arr)
ans += 1
log(2, ans, leaves[ans-1])
return ans
def solve(n, k, edges):
if k < 3:
return k
graph = build_graph(n, edges)
log(9, "graph:", graph)
leaves = []
for i in xrange(1, n+1):
if len(graph[i]) == 1:
node = Node(i, graph[i].keys()[0])
leaves.append(node)
log(9, "leaves:", leaves)
m = n - k
ans = len(leaves)
while m > 0 and ans > 2:
next_leaves = []
for leaf in leaves:
p = leaf.parent
log(9, "node:", p, graph[p])
graph[p].pop(leaf.num)
if len(graph[p]) == 1:
gp = graph[p].keys()[0]
leaf.num = p
leaf.parent = gp
leaf.weight += 1
next_leaves.append(leaf)
else:
m -= leaf.weight
if m >= 0:
ans -= 1
else:
break
leaves = next_leaves
return max(2, ans)
def main():
t = int(raw_input())
for _ in xrange(t):
n, k = map(int, raw_input().split())
edges = []
for _ in xrange(n-1):
e = map(int, raw_input().split())
edges.append(e)
ans = solve(n, k, edges)
print ans
def alternate():
n = 100
same = True
edges = [[1, 2], [2, 3], [3, 4], [3, 5]]
k = 5
m = 0
while same:
log(9, "solve")
ans = solve(len(edges)+1, k ,edges)
log(9, "fast")
ans_brute = solve_brute(len(edges)+1, k, edges)
if ans_brute != ans:
same = False
print n, k, edges
print ans
print ans_brute
edges = []
for i in xrange(2, n + 1):
edges.append([randint(1, i-1), i])
k = randint(1, n)
m += 1
if m%1000 == 0:
print m
exit(0)
if __name__ == '__main__':
#alternate()
main()
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace CSharpSolution.JUNE21C.SUBTRCOV
{
class Tree
{
//public List<int> minWithout;
//public List<int> minWith;
public LinkedList<Tree> children;
//public bool done = false;
//public int depth = 0;
public int impact = -1;
//public int id;
public Tree()
{
//minWithout = new List<int>();
//minWith = new List<int>();
//minWithout.Add(0); // 0 nodes -> 0
//minWith.Add(0); // 0 nodes -> 0
//minWith.Add(1); // 1 node -> 1
children = new LinkedList<Tree>();
//this.id = id;
}
public void AddChild(Tree t)
{
children.AddLast(t);
}
/* public bool AllChildrenDone()
{
int notDone = 0;
foreach (Tree t in children)
{
if (!t.done)
{
notDone++;
}
if (notDone > 1)
{
return false;
} // else // We are a leaf node, our only child is the parent.
}
return true;
}*/
public void ComputeImpact()
{
impact = 1;
Debug.Assert(children.Count == 1);
Tree target = children.First();
Tree previous = this;
while (target.children.Count == 2)
{
impact++;
if (target.children.First() == previous)
{
previous = target;
target = target.children.Last();
}
else
{
previous = target;
target = target.children.First();
}
}
}
public void UpdateParent()
{
// We are removing this leaf, first we need to remove all nodes as long as they are leafes
Debug.Assert(children.Count == 1);
Tree target = children.First();
Tree previous = this;
while (target.children.Count == 2)
{
if (target.children.First() == previous)
{
previous = target;
target = target.children.Last();
}
else
{
previous = target;
target = target.children.First();
}
}
// We now have our target, it should no longer point to the previous one
target.children.Remove(previous);
// If this now becomes part of a chain, we need to update the ends of the chain:
Debug.Assert(target.children.Count >= 2);
if (target.children.Count == 2)
{
// Go up and down to update both ends
Tree targetUp = target.children.First();
Tree previousUp = target;
int stepsUp = 0;
int stepsDown = 0;
// UP/DOWN
while (targetUp.children.Count == 2)
{
stepsUp++;
if (targetUp.children.First() == previousUp)
{
previousUp = targetUp;
targetUp = targetUp.children.Last();
}
else
{
previousUp = targetUp;
targetUp = targetUp.children.First();
}
}
Tree targetDown = target.children.Last();
Tree previousDown = target;
while (targetDown.children.Count == 2)
{
stepsDown++;
if (targetDown.children.First() == previousDown)
{
previousDown = targetDown;
targetDown = targetDown.children.Last();
}
else
{
previousDown = targetDown;
targetDown = targetDown.children.First();
}
}
if (targetUp.children.Count == 1)
{
// targetUp is a leaf, add new impact
targetUp.impact += stepsDown + 1;
if (targetDown.children.Count == 1)
{
targetUp.impact++;
}
}
if (targetDown.children.Count == 1)
{
// targetDown is a leaf, add new impact
targetDown.impact += stepsUp + 1;
if (targetUp.children.Count == 1)
{
targetDown.impact++;
}
}
}
}
/*
public void UpdateSelf(int maxK)
{
// A bit of safety margin because we access [2] explicitly
maxK = Math.Max(maxK, 3);
done = true;
var childrenDone = new List<Tree>();
foreach (var c in children)
{
if (c.done)
{
childrenDone.Add(c);
}
}
if (childrenDone.Count == 0)
{
return;
}
// We have to fill data up to the maximum size
// First our depth
int maxDepth = 0;
int maxNodeCount = 0;
foreach (Tree c in childrenDone)
{
maxDepth = Math.Max(maxDepth, c.depth);
maxNodeCount += Math.Max(c.minWith.Count, c.minWithout.Count);
}
// Increase by one to account for us
maxDepth++;
maxNodeCount++;
maxNodeCount = Math.Min(maxK + 1, maxNodeCount);
depth = maxDepth;
// Now the tricky part
while (minWithout.Count <= maxNodeCount)
{
minWithout.Add(0);
}
while (minWith.Count <= maxNodeCount)
{
minWith.Add(0);
}
// We can join trees together, this will include us if we don't just copy the value from one tree +1
// We add one tree after another
foreach (Tree c in childrenDone)
{
var newWith = new List<int>(minWith);
var newWithout = new List<int>(minWithout);
// For j=1 we would remove the whole tree, no good
for (int j = 1; j < c.minWith.Count; j++)
{
if (c.minWith[j] == 0)
{
continue;
}
if (j == 1)
{
// For j=1 we would drop the whole tree, unless we keep it as a single node
// that we add to our exisiting tree.
// If we add it additional to our root, we can just add 1 for our root
for (int i = 1; i < newWith.Count; i++)
{
newWith[i] = Math.Max(newWith[i], minWith[i - 1] + 1);
}
// If we add it and we don't have our root then that would include
// our root automatically (us+root) = +2 total and +1 node count
// Problem is that we might already include the root node.
// So the proper way it to base this of the case where we include the root node
// and just move the root node to our new position
for (int i = 2; i < newWithout.Count; i++)
{
newWithout[i] = Math.Max(newWithout[i], minWith[i] + 1);
}
continue;
}
// J=2 and this includes the root node, if we join it with either us
// or another tree, we can remove the root node -> get one for free
// First option just put as as root (the number of nodes stays but we add one node (us))
newWith[j] = Math.Max(newWith[j], 1 + c.minWith[j]);
// Second Option, join it with another subtree
for (int i = 1; i + j - 1 < minWithout.Count; i++)
{
if (minWithout[i] == 0)
{
// No method of achieving this
continue;
}
// -1 because we no longer need the root node from C
int target = i + j - 1;
int total = minWithout[i] + c.minWith[j];
if (total > newWithout[target])
{
newWithout[target] = total;
}
}
// Third option, we can just move the root node up
for (int i = 1; i + j - 1 < minWith.Count; i++)
{
if (minWith[i] == 0)
{
// No method of achieving this
continue;
}
// -1 because we no longer need the root node from C
int target = i + j - 1;
int total = minWith[i] + c.minWith[j];
if (total > newWith[target])
{
newWith[target] = total;
}
if (i > 1)
{
// If we have the root node and some other side tree
// we could also give up the root of both us and the side tree
target = i + j - 2;
newWithout[target] = Math.Max(newWithout[target], minWith[i] + c.minWith[j]);
}
}
}
minWith = newWith;
minWithout = newWithout;
// With us as root
if (c.depth + 2 > minWith[2])
{
minWith[2] = c.depth + 2;
}
// Without Us 1
for (int j = 1; j < c.minWithout.Count; j++)
{
minWithout[j] = Math.Max(minWithout[j], c.minWithout[j]);
}
// Without Us 2
for (int j = 1; j < c.minWith.Count; j++)
{
minWithout[j] = Math.Max(minWithout[j], c.minWith[j]);
}
}
int max = 0;
foreach (int i in minWith)
{
max = Math.Max(i, max);
}
int firstLower = minWith.Count;
for (int i = minWith.Count - 1; i > 0; i--)
{
if (minWith[i] < max)
{
firstLower = i;
}
else
{
break;
}
}
if (firstLower < minWith.Count)
{
minWith.RemoveRange(firstLower, minWith.Count - firstLower);
}
max = 0;
foreach (int i in minWithout)
{
max = Math.Max(i, max);
}
firstLower = minWithout.Count;
for (int i = minWithout.Count - 1; i > 0; i--)
{
if (minWithout[i] < max)
{
firstLower = i;
}
else
{
break;
}
}
if (firstLower < minWithout.Count)
{
minWithout.RemoveRange(firstLower, minWithout.Count - firstLower);
}
}*/
}
class SUBTRCOV
{
/*
static int SmallestSubset(List<Tree> nodes, int k)
{
if (k <= 1)
{
return 1;
}
int maxK = 0;
foreach (Tree t in nodes)
{
if (t.children.Count == 1)
{
// Leaf node!
maxK++;
}
}
Queue<Tree> toDo = new Queue<Tree>(nodes);
while (toDo.Count > 0)
{
var node = toDo.Dequeue();
// Check if all children are known, otherwise put it back in the queue
// In order to call this function multiple times, skip things that are done
if (node.done)
{
continue;
}
if (node.AllChildrenDone())
{
node.UpdateSelf(maxK);
}
else
{
toDo.Enqueue(node);
}
}
// Do this only once we are done
int minV = int.MaxValue;
foreach (Tree node in nodes)
{
for (int i = 1; i < node.minWithout.Count && i < minV; i++)
{
if (node.minWithout[i] >= k)
{
minV = i;
break;
}
}
for (int i = 1; i < node.minWith.Count && i < minV; i++)
{
if (node.minWith[i] >= k)
{
minV = i;
break;
}
}
}
if (minV > nodes.Count)
{
throw new Exception("Not possible");
}
return minV;
}*/
static Tree getWorstTree(List<Tree> leafes)
{
Tree lowest = leafes[0];
for (int i = 0; i < leafes.Count; i++)
{
if (leafes[i].impact < lowest.impact)
lowest = leafes[i];
}
return lowest;
}
static int SmallestSubsetV2(List<Tree> nodes, int k)
{
if (k <= 1)
{
return 1;
}
List<Tree> leafes = new List<Tree>();
foreach (Tree t in nodes)
{
if (t.children.Count == 1)
{
// Leaf node!
t.ComputeImpact();
leafes.Add(t);
}
}
int currentCover = nodes.Count;
int currentSSize = leafes.Count;
leafes.Sort((t1, t2) => t2.impact.CompareTo(t1.impact));
int[] bestTreePossible = new int[leafes.Count];
for (int i = 0; i < leafes.Count; i++)
{
bestTreePossible[i] = leafes[i].impact;
}
int counter = leafes.Count - 1;
int foundLast = bestTreePossible[counter];
int LC = leafes.Count;
int LCM = LC - 1;
while (currentCover > k && LC > 0)
{
// Remove the leaf with the lowest number:
int lowestIdx = LCM;
int lowestValue = leafes[lowestIdx].impact;
if (foundLast != lowestValue)
{
for (int i = LCM; i >= 0; i--)
{
if (leafes[i].impact < lowestValue)
{
lowestIdx = i;
lowestValue = leafes[i].impact;
if (foundLast == lowestValue)
{
break;
}
}
}
}
foundLast = Math.Min(lowestValue, bestTreePossible[counter]);
if (currentCover - lowestValue < k)
{
// Too much impact
break;
}
currentCover -= lowestValue;
currentSSize--;
leafes[lowestIdx].UpdateParent();
// Make sure we don't consider this one
leafes.RemoveAt(lowestIdx);
LC--;
LCM--;
counter--;
if (LC > 1000 && LC - lowestIdx > 300)
{
leafes.Sort((t1, t2) => t2.impact.CompareTo(t1.impact));
for (int i = 0; i < LC; i++)
{
bestTreePossible[i] = leafes[i].impact;
}
}
}
return currentSSize;
}
static void Main(string[] args)
{
// System.IO.StreamWriter file = new System.IO.StreamWriter("output.txt", append: true);
int t = int.Parse(Console.ReadLine());
for (int i = 0; i < t; i++)
{
string line = Console.ReadLine();
int split = line.IndexOf(' ');
int n = int.Parse(line.Substring(0, split));
int k = int.Parse(line.Substring(split));
List<Tree> nodes = new List<Tree>(n);
for (int j = 0; j < n; j++)
{
nodes.Add(new Tree());
}
for (int j = 0; j < n - 1; j++)
{
line = Console.ReadLine();
split = line.IndexOf(' ');
int from = int.Parse(line.Substring(0, split)) - 1;
int to = int.Parse(line.Substring(split)) - 1;
nodes[from].AddChild(nodes[to]);
nodes[to].AddChild(nodes[from]);
}
/*Console.WriteLine("Debug Output");
// Remove
for (int kS = 1; kS <= nodes.Count; kS++)
{
Console.WriteLine($"k:{kS:00} S:{SmallestSubset(nodes, kS)}");
}*/
//file.WriteLine(SmallestSubset(nodes, k));
Console.WriteLine(SmallestSubsetV2(nodes, k));
}
//file.Close();
//Console.WriteLine("Done");
}
}
}
package main
import (
"bufio"
"bytes"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var buf bytes.Buffer
tc := readNum(reader)
for tc > 0 {
tc--
n, m := readTwoNums(reader)
E := make([][]int, n-1)
for i := 0; i < n-1; i++ {
E[i] = readNNums(reader, 2)
}
res := solve(n, E, m)
buf.WriteString(fmt.Sprintf("%d\n", res))
}
fmt.Print(buf.String())
}
func readInt(bytes []byte, from int, val *int) int {
i := from
sign := 1
if bytes[i] == '-' {
sign = -1
i++
}
tmp := 0
for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
tmp = tmp*10 + int(bytes[i]-'0')
i++
}
*val = tmp * sign
return i
}
func readNum(reader *bufio.Reader) (a int) {
bs, _ := reader.ReadBytes('\n')
readInt(bs, 0, &a)
return
}
func readTwoNums(reader *bufio.Reader) (a int, b int) {
res := readNNums(reader, 2)
a, b = res[0], res[1]
return
}
func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
res := readNNums(reader, 3)
a, b, c = res[0], res[1], res[2]
return
}
func readNNums(reader *bufio.Reader, n int) []int {
res := make([]int, n)
x := 0
bs, _ := reader.ReadBytes('\n')
for i := 0; i < n; i++ {
for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
x++
}
x = readInt(bs, x, &res[i])
}
return res
}
func readUint64(bytes []byte, from int, val *uint64) int {
i := from
var tmp uint64
for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
tmp = tmp*10 + uint64(bytes[i]-'0')
i++
}
*val = tmp
return i
}
func solve(n int, E [][]int, k int) int {
g := NewGraph(n, len(E)*2)
for _, e := range E {
g.AddEdge(e[0]-1, e[1]-1)
g.AddEdge(e[1]-1, e[0]-1)
}
dist := make([]int, n)
var dfs func(p, u int)
dfs = func(p, u int) {
for i := g.nodes[u]; i > 0; i = g.next[i] {
v := g.to[i]
if p != v {
dist[v] = dist[u] + 1
dfs(u, v)
}
}
}
dfs(0, 0)
var root int
for i := 0; i < n; i++ {
if dist[i] > dist[root] {
root = i
}
}
var time = -1
eu := make([]int, n)
open := make([]int, n)
end := make([]int, n)
P := make([]int, n)
var dfs2 func(p, u int)
dfs2 = func(p, u int) {
time++
eu[time] = u
open[u] = time
for i := g.nodes[u]; i > 0; i = g.next[i] {
v := g.to[i]
if v != p {
P[v] = u
dist[v] = dist[u] + 1
dfs2(u, v)
}
}
end[u] = time
}
dist[root] = 0
dfs2(root, root)
lt := NewLazyTree(n)
for i := 0; i < n; i++ {
lt.Update(open[i], open[i], dist[i])
}
set := make([]bool, n)
set[root] = true
lt.Update(open[root], open[root], -(n + 1))
ans := 1
k--
for k > 0 {
pair := lt.Query(0, n-1)
u := eu[pair[0]]
add := pair[1]
ans++
for cur := u; !set[cur]; cur = P[cur] {
k--
lt.Update(open[cur], open[cur], -(n + 1))
set[cur] = true
for i := g.nodes[cur]; i > 0; i = g.next[i] {
v := g.to[i]
if P[cur] == v || set[v] {
continue
}
lt.Update(open[v], end[v], -add)
}
add--
}
}
return ans
}
type Graph struct {
nodes []int
next []int
to []int
cur int
}
func NewGraph(n int, e int) *Graph {
g := new(Graph)
g.nodes = make([]int, n)
g.next = make([]int, e+3)
g.to = make([]int, e+3)
g.cur = 0
return g
}
func (g *Graph) AddEdge(u, v int) {
g.cur++
g.next[g.cur] = g.nodes[u]
g.nodes[u] = g.cur
g.to[g.cur] = v
}
type LazyTree struct {
tree []int
lazy []int
ind []int
n int
m int
}
func NewLazyTree(n int) *LazyTree {
m := 1
for m < n {
m <<= 1
}
lt := new(LazyTree)
lt.n = n
lt.m = m
lt.tree = make([]int, m<<1)
lt.lazy = make([]int, m<<1)
lt.ind = make([]int, m<<1)
for i := m; i < len(lt.ind); i++ {
lt.ind[i] = i - m
}
for i := m - 1; i > 0; i-- {
if lt.tree[i*2] <= lt.tree[i*2+1] {
lt.ind[i] = lt.ind[2*i]
} else {
lt.ind[i] = lt.ind[2*i+1]
}
}
return lt
}
func (lt *LazyTree) push(i int) {
if lt.lazy[i] != 0 {
lt.tree[i] += lt.lazy[i]
if i < lt.m {
lt.lazy[i*2] += lt.lazy[i]
lt.lazy[i*2+1] += lt.lazy[i]
}
lt.lazy[i] = 0
}
}
func (lt *LazyTree) Query(l, r int) []int {
var loop func(l, r int, ll, rr int, i int) []int
loop = func(l, r int, ll, rr int, i int) []int {
if l == ll && r == rr {
return []int{lt.ind[i], lt.tree[i]}
}
mid := (ll + rr) / 2
if r <= mid {
return loop(l, r, ll, mid, i*2)
}
if mid < l {
return loop(l, r, mid+1, rr, i*2+1)
}
a := loop(l, mid, ll, mid, i*2)
b := loop(mid+1, r, mid+1, rr, i*2+1)
if a[1] >= b[1] {
return a
}
return b
}
return loop(l, r, 0, lt.m-1, 1)
}
func (lt *LazyTree) Update(l, r int, x int) {
var loop func(l, r, ll, rr int, i int)
loop = func(l, r, ll, rr int, i int) {
lt.push(i)
if l == ll && r == rr {
lt.lazy[i] += x
lt.push(i)
return
}
mid := (ll + rr) / 2
if r <= mid {
loop(l, r, ll, mid, i*2)
lt.push(2*i + 1)
} else if mid < l {
lt.push(2 * i)
loop(l, r, mid+1, rr, i*2+1)
} else {
loop(l, mid, ll, mid, i*2)
loop(mid+1, r, mid+1, rr, i*2+1)
}
lt.tree[i] = max(lt.tree[2*i], lt.tree[2*i+1])
if lt.tree[i] == lt.tree[2*i] {
lt.ind[i] = lt.ind[2*i]
} else {
lt.ind[i] = lt.ind[2*i+1]
}
}
loop(l, r, 0, lt.m-1, 1)
}
func max(a, b int) int {
if a >= b {
return a
}
return b
}
In our experience, we suggest you solve this Minimum Subtree Cover CodeChef Solution and gain some new skills from Professionals completely free and we assure you will be worth it.
If you are stuck anywhere between any coding problem, just visit Queslers to get the Minimum Subtree Cover CodeChef Solution.
I hope this Minimum Subtree Cover CodeChef Solution would be useful for you to learn something new from this problem. If it helped you then don’t forget to bookmark our site for more Coding Solutions.
This Problem is intended for audiences of all experiences who are interested in learning about Programming Language in a business context; there are no prerequisites.
Keep Learning!