Problem:
H: Colorful Tree
Story
Yamiuchi
(assassination) is a traditional event that is held annually in JAG summer camp. Every team displays a decorated tree in the dark and all teams' trees are compared from the point of view of their colorfulness. In this competition, it is allowed to cut the other teams’ tree to reduce its colorfulness. Despite a team would get a penalty if it were discovered that the team cuts the tree of another team, many teams do this obstruction.
You decided to compete in
Yamiuchi
and write a program that maximizes the colorfulness of your team’s tree. The program has to calculate maximum scores for all subtrees in case the other teams cut your tree.
Problem Statement
You are given a rooted tree
G
with
N
vertices indexed with
1
through
N
. The root is vertex
1
. There are
K
kinds of colors indexed with
1
through
K
. You can paint vertex
i
with either color
c_i
or
d_i
. Note that
c_i = d_i
may hold, and if so you have to paint vertex
i
with
c_i
(
=d_i
).
Let the colorfulness of tree
T
be the number of different colors in
T
. Your task is to write a program that calculates maximum colorfulness for all rooted subtrees. Note that coloring for each rooted subtree is done independently, so previous coloring does not affect to other coloring.
Input
N
K
u_1
v_1
:
u_{N-1}
v_{N-1}
c_1
d_1
:
c_N
d_N
The first line contains two integers
N
and
K
in this order.
The following
N-1
lines provide information about the edges of
G
. The
i
-th line of them contains two integers
u_i
and
v_i
, meaning these two vertices are connected with an edge.
The following
N
lines provide information about color constraints. The
i
-th line of them contains two integers
c_i
and
d_i
explained above.
Constraints
1 \leq N \leq 10^5
1 \leq K \leq 2\times 10^5
1 \leq u_i , v_i \leq N
1 \leq c_i , d_i \leq K
The input graph is a tree.
All inputs are integers.
Output
Output
N
lines.
The
i
-th line of them contains the maximum colorfulness of the rooted subtree of
G
whose root is
i
.
Sample Input 1
2 10
1 2
1 9
8 7
Output for Sample Input 1
2
1
Sample Input 2
3 2
1 2
1 3
1 2
1 1
1 2
Output for Sample Input 2
2
1
1
Note that two color options of a vertex can be the same.
Sample Input 3
5 100000
4 3
3 5
1 3
2 1
3 2
1 3
2 1
4 2
1 4
Output for Sample Input 3
4
1
3
1
1

Submitted solutions:

code_snippet: // clang-format off
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i, n) for (ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template<class A, class B>
bool chmax(A &a, B b) { return a < b && (a = b, true); }
template<class A, class B>
bool chmin(A &a, B b) { return b < a && (a = b, true); }

struct UnionFind {
  unordered_map<int, int> p;
  unordered_map<int, bool> is_tree;
  int ntrees = 0;
  void new_node(int a) {
      assert(!p.contains(a));
      p[a] = -1;
      is_tree[a] = true;
      ntrees++;
  }
  void merge(int a, int b) {
    int x = group(a), y = group(b);
    if (x == y) {
        if(is_tree[x]) {
            is_tree[x] = false;
            ntrees--;
        }
        return;
    }
    if (-p[x] < -p[y]) swap(x, y);
    p[x] += p[y];
    p[y] = x;
    ntrees -= is_tree[x];
    ntrees -= is_tree[y];
    is_tree[x] &= is_tree[y];
    ntrees += is_tree[x];
  }
  void add_edge(int a, int b) {
      if(!p.contains(a)) new_node(a);
      if(!p.contains(b)) new_node(b);
      merge(a, b);
  }
  int size(int a) { return -p[group(a)]; }
  int group(int a) {
    assert(p.contains(a));
    if (p[a] < 0) return a;
    return p[a] = group(p[a]);
  }
  bool same(int a, int b) {
    return group(a) == group(b);
  }
};

void solve(){
    int n, k; cin >> n >> k;
    V<V<pair<int, int>>> es(n);
    V<V<int>> g(n);
    REP(i, n-1) {
        int u, v; cin >> u >> v; u--; v--;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    V<UnionFind> ufs(n);
    REP(i, n) {
        int c, d; cin >> c >> d; c--; d--;
        es[i].emplace_back(c, d);
        ufs[i].add_edge(c, d);
    }
    V<int> par(n, -1);
    stack<int> stk;
    stk.push(~0);
    stk.push(0);
    V<int> ans(n);
    while(!stk.empty()) {
        int u = stk.top(); stk.pop();
        if(u >= 0) {
            for(int v : g[u]) {
                if(v == par[u]) continue;
                par[v] = u;
                stk.push(~v);
                stk.push(v);
            }
        } else {
            u = ~u;
            for(int v : g[u]) {
                if(v == par[u]) continue;
                if(ssize(es[u]) < ssize(es[v])) {
                    swap(es[u], es[v]);
                    swap(ufs[u], ufs[v]);
                }
                for(auto [c, d] : es[v]) {
                    es[u].emplace_back(c, d);
                    ufs[u].add_edge(c, d);
                }
            }
            ans[u] = ssize(ufs[u].p) - ufs[u].ntrees;
        }
    }
    REP(i, n) cout << ans[i] << '\n';
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    solve();
}
accuracy: 1
time_ms: 330
memory_kb: 178468
final_rank: 10

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define fi first
#define se second
#define kill _z_kill
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define outval(x) cerr<<#x" = "<<x<<endl
#define outv(x) cerr<<#x" = "<<x<<"  "
#define outtag(x) cerr<<"--------------"#x"---------------"<<endl
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
	For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
#define User_Time ((double)clock()/CLOCKS_PER_SEC)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned uint;
typedef long double LD;
typedef vector <int> vi;
typedef pair <int,int> pii;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
//int Pow(int x,int y){
//	int ans=1;
//	for (;y;y>>=1,x=(LL)x*x%mod)
//		if (y&1)
//			ans=(LL)ans*x%mod;
//	return ans;
//}
//void Add(int &x,int y){
//	if ((x+=y)>=mod)
//		x-=mod;
//}
//void Del(int &x,int y){
//	if ((x-=y)<0)
//		x+=mod;
//}
//int Add(int x){
//	return x>=mod?x-mod:x;
//}
//int Del(int x){
//	return x<0?x+mod:x;
//}
//void ckmax(int &x,int y){
//	if (x<y)
//		x=y;
//}
//void ckmin(int &x,int y){
//	if (x>y)
//		x=y;
//}
const int N=200005;
int n,k;
vi e[N],id[N];
int sz[N],son[N];
int a[N],b[N];
int ans[N];
void dfs(int x,int pre){
	sz[x]=1;
	for (auto y : e[x]){
		if (y==pre)
			continue;
		dfs(y,x);
		sz[x]+=sz[y];
		if (!son[x]||sz[y]>sz[son[x]])
			son[x]=y;
	}
}
int fa[N],c[N],sc[N];
int getf(int x){
	return fa[x]==x?x:fa[x]=getf(fa[x]);
}
int fuck(int x){
	assert(c[x]>=sc[x]-1);
	return min(c[x],sc[x]);
}
void init(int z){
	fa[z]=z,sc[z]=1,c[z]=0;
}
void adde(int i,int x,int y){
	int fx=getf(x),fy=getf(y);
//	outval(fx),outval(fy);
//	outval(fuck(fx)),outval(fuck(fy));
	ans[i]-=fuck(fx);
	if (fx!=fy){
		ans[i]-=fuck(fy);
		fa[fy]=fx;
		c[fx]+=c[fy];
		sc[fx]+=sc[fy];
	}
	c[fx]++;
//	outval(fuck(fx));
	ans[i]+=fuck(fx);
}
void solve(int x,int pre){
	for (auto y : e[x])
		if (y!=pre&&y!=son[x]){
			solve(y,x);
			for (auto z : id[y]){
				init(a[z]);
				init(b[z]);
			}
		}
	int y=son[x];
	if (y){
		solve(y,x);
		ans[x]=ans[y];
		swap(id[x],id[y]);
	}
	id[x].pb(x);
	adde(x,a[x],b[x]);
	for (auto y : e[x])
		if (y!=pre&&y!=son[x]){
			for (auto z : id[y]){
				id[x].pb(z);
				adde(x,a[z],b[z]);
			}
		}
}
int main(){
	n=read(),k=read();
	For(i,1,n-1){
		int x=read(),y=read();
		e[x].pb(y),e[y].pb(x);
	}
	For(i,1,n)
		a[i]=read(),b[i]=read();
	For(i,1,k)
		sc[i]=1,fa[i]=i;
	dfs(1,0);
	solve(1,0);
	For(i,1,n)
		printf("%d\n",ans[i]);
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 29848
final_rank: 2

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

const int NMAX = 100005;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(int n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

int N, K;
vector<int> adj[NMAX];
int cval[NMAX], dval[NMAX];

struct Data {
    unordered_set<int> forced;
    vector<pair<int,int>> freeVertices;
    vector<int> assigned;
    unordered_map<int,int> matchR;
};

vector<int> vis;
int curStamp = 0;

bool tryAssign(Data &D, int freeIdx) {
    int a = D.freeVertices[freeIdx].first;
    int b = D.freeVertices[freeIdx].second;
    for (int candidate : {a, b}) {
        if(D.forced.count(candidate)) continue;
        if(vis[candidate] == curStamp) continue;
        vis[candidate] = curStamp;
        if(D.matchR.find(candidate) == D.matchR.end()){
            D.matchR[candidate] = freeIdx;
            D.assigned[freeIdx] = candidate;
            return true;
        }
        int other = D.matchR[candidate];
        if(tryAssign(D, other)){
            D.matchR[candidate] = freeIdx;
            D.assigned[freeIdx] = candidate;
            return true;
        }
    }
    return false;
}

void addFreeVertex(Data &D, pair<int,int> freePair) {
    int idx = D.freeVertices.size();
    D.freeVertices.push_back(freePair);
    D.assigned.push_back(0);
    curStamp++;
    tryAssign(D, idx);
}

void updateForForced(Data &D, int forcedColor) {
    if(D.forced.count(forcedColor)) return;
    D.forced.insert(forcedColor);
    if(D.matchR.find(forcedColor) != D.matchR.end()){
        int freeIdx = D.matchR[forcedColor];
        D.matchR.erase(forcedColor);
        D.assigned[freeIdx] = 0;
        curStamp++;
        tryAssign(D, freeIdx);
    }
}

void mergeData(Data &dest, Data &src) {
    for (auto col : src.forced) {
        if(dest.forced.count(col) == 0) updateForForced(dest, col);
    }
    for (auto &pr : src.freeVertices) addFreeVertex(dest, pr);
}

Data dfs(int v, int parent, vector<Data> &dp) {
    Data cur;
    if(cval[v] == dval[v]) cur.forced.insert(cval[v]);
    else addFreeVertex(cur, {cval[v], dval[v]});

    for (int nxt : adj[v]) {
        if(nxt == parent) continue;
        Data child = dfs(nxt, v, dp);
        if(child.freeVertices.size() + child.forced.size() > cur.freeVertices.size() + cur.forced.size()){
            mergeData(child, cur);
            cur = move(child);
        } else mergeData(cur, child);
    }
    int ans_v = cur.forced.size() + cur.matchR.size();
    dp[v].forced = cur.forced;
    dp[v].freeVertices = cur.freeVertices;
    dp[v].assigned = cur.assigned;
    dp[v].matchR = cur.matchR;
    static vector<int> ansArr(NMAX, 0);
    ansArr[v] = ans_v;
    return cur;
}

int main() {
    N = Cin(), K = Cin();
    for (int i = 1; i <= N-1; i++){
        int u = Cin(), v = Cin();
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    for (int i = 1; i <= N; i++) cval[i] = Cin(), dval[i] = Cin();

    vis.assign(K+1, 0);
    vector<Data> dp(N+1);
    vector<int> ansArr(N+1, 0);

    function<Data(int, int)> dfs2 = [&](int v, int parent) -> Data {
        Data cur;
        if(cval[v] == dval[v]) cur.forced.insert(cval[v]);
        else addFreeVertex(cur, {cval[v], dval[v]});

        for (int nxt : adj[v]){
            if(nxt == parent) continue;
            Data child = dfs2(nxt, v);
            if(child.freeVertices.size() + child.forced.size() > cur.freeVertices.size() + cur.forced.size()){
                mergeData(child, cur);
                cur = move(child);
            } else mergeData(cur, child);
        }
        ansArr[v] = cur.forced.size() + cur.matchR.size();
        return cur;
    };

    dfs2(1, 0);
    for (int i = 1; i <= N; i++) Cout(ansArr[i]);
    return 0;
}
accuracy: 1
time_ms: 790
memory_kb: 66328
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#define int long long
#define ri register int
#define N 200005
using namespace std;
struct S {
	int top,ans,p[N],fa[N],sz[N],stk[N];
	inline void init(int n) {
		for (ri i=1; i<=n; i++) fa[i]=i,sz[i]=1;
	}
	int fnd(int x) {
		return fa[x]^x?fa[x]=fnd(fa[x]):x;
	}
	inline void link(int x,int y) {
		int fx=fnd(x),fy=fnd(y);
		if (fx==fy) {
			if (++p[fx]==1) ans++;
			stk[++top]=-fx;
			return;
		}
		if (sz[fx]<sz[fy]) swap(fx,fy);
		if (p[fx]&&p[fy]) ans--;
		fa[fy]=fx,sz[fx]+=sz[fy],p[fx]+=p[fy],ans++,stk[++top]=fy;
	}
	inline void back(int x) {
		for (ri t; top>x; top--)
			if (stk[top]>0) {
				t=stk[top],sz[fa[t]]-=sz[t],p[fa[t]]-=p[t];
				if (p[t]&&p[fa[t]]) ans++;
				fa[t]=t,ans--;
			} else {
				t=-stk[top];
				if (p[t]==1) ans--;
				p[t]--;
			}
	}
} s;
struct edge {
	int u,v;
} e[N<<1]= {0};
int n,k,t,tot=0,h[N]= {0},a[N]= {0},b[N]= {0},fa[N]= {0},sz[N]= {0},ms[N]= {0},ans[N]= {0};
template <typename T> inline void read(T &x) {
    T c=getchar(),f=0;
    for (; c<48||57<c; c=getchar()) if (c=='-') f=1;
    for (x=0; 48<=c&&c<=57; c=getchar()) x=(x<<3)+(x<<1)+(c^48);
    if (f) x=-x;
}
template <typename T> inline void print(T x) {
    if (x<0) x=-x,putchar('-');
    if (x>9) print(x/10);
    putchar(x%10+48);
}
inline void add(int u,int v) {
	e[++tot]=(edge) {h[u],v},h[u]=tot;
}
void dfs(int x) {
	sz[x]=1;
	for (ri i=h[x]; i; i=e[i].u)
		if (e[i].v^fa[x]) {
			fa[e[i].v]=x,dfs(e[i].v),sz[x]+=sz[e[i].v];
			if (sz[e[i].v]>sz[ms[x]]) ms[x]=e[i].v;
		}
}
void push(int x) {
	s.link(a[x],b[x]);
	for (ri i=h[x]; i; i=e[i].u)
		if (e[i].v^fa[x]) push(e[i].v);
}
void solve(int x) {
	for (ri i=h[x]; i; i=e[i].u)
		if (e[i].v^fa[x]&&e[i].v^ms[x]) t=s.top,solve(e[i].v),s.back(t);
	if (ms[x]) solve(ms[x]);
	s.link(a[x],b[x]);
	for (ri i=h[x]; i; i=e[i].u)
		if (e[i].v^fa[x]&&e[i].v^ms[x]) push(e[i].v);
	ans[x]=s.ans;
}
signed main() {
	read(n),read(k);
	for (ri i=1,x,y; i<n; i++) read(x),read(y),add(x,y),add(y,x);
	for (ri i=1; i<=n; i++) read(a[i]),read(b[i]);
	s.init(k),dfs(1),solve(1);
	for (ri i=1; i<=n; i++) print(ans[i]),putchar('\n');
    return 0;
}
accuracy: 0.2807017543859649
time_ms: 30
memory_kb: 32416
final_rank: 16

code_snippet: #include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define m_k make_pair
using namespace std;
const int N=2*1e5+100;
int n,k,sz[N],son[N],id[N],ans[N];
int c[N],d[N],cnt,ti[N],dfn;
int tot,first[N],nxt[N*2],point[N*2];
namespace dsu
{
	struct node
	{
		int x,y,e,sz,T;//x->y
	};
	int fa[N],e[N],sz[N];
	stack <node> s;
	int nowtime()
	{
		if (s.empty()) return 0;
		else return s.top().T;
	}
	inline int find(int x)
	{
		if (fa[x]==x) return fa[x];
		return find(fa[x]);
	}
	void init()
	{
		for (int i=1;i<=k;i++) fa[i]=i,sz[i]=1;
	}
	void connect(int x,int y)
	{
		int fax=find(x),fay=find(y),T=nowtime()+1;
		if (fax==fay)
		{
			s.push((node){fax,fay,e[fax],sz[fax],T});
			cnt-=sz[fax]-(e[fax]==sz[fax]-1);
			e[fax]++;
			cnt+=sz[fax]-(e[fax]==sz[fax]-1);
			return;
		}
		if (sz[fax]>sz[fay]) swap(fax,fay);
		cnt-=sz[fax]-(e[fax]==sz[fax]-1);
		cnt-=sz[fay]-(e[fay]==sz[fay]-1);
		s.push((node){fax,fay,e[fay],sz[fay],T});
		fa[fax]=fay,sz[fay]+=sz[fax],e[fay]+=e[fax]+1;
		cnt+=sz[fay]-(e[fay]==sz[fay]-1);
	}
	void back(int T)
	{
		while (!s.empty() && s.top().T>T)
		{
			node tmp=s.top();
			s.pop();
			cnt-=sz[tmp.y]-(e[tmp.y]==sz[tmp.y]-1);
			fa[tmp.x]=tmp.x,e[tmp.y]=tmp.e,sz[tmp.y]=tmp.sz;
			cnt+=sz[tmp.x]-(e[tmp.x]==sz[tmp.x]-1);
			cnt+=sz[tmp.y]-(e[tmp.y]==sz[tmp.y]-1);
		}
	}
}
void add_edge(int x,int y)
{
	tot++;
	nxt[tot]=first[x];
	first[x]=tot;
	point[tot]=y;
}
void dfs(int x,int fa)
{
	sz[x]=1;
	for (int i=first[x];i!=-1;i=nxt[i])
	{
		int u=point[i];
		if (u==fa) continue;
		dfs(u,x);
		sz[x]+=sz[u];
		if (sz[u]>sz[son[x]]) son[x]=u;
	}
}
void dfs1(int x,int fa)
{
	dsu::connect(c[x],d[x]);
	for (int i=first[x];i!=-1;i=nxt[i])
	{
		int u=point[i];
		if (u==fa) continue;
		dfs1(u,x);
	}
}
void dfs2(int x,int fa)
{
	for (int i=first[x];i!=-1;i=nxt[i])
	{
		int u=point[i],t=dsu::nowtime();
		if (u==fa || u==son[x]) continue;
		dfs2(u,x);
		dsu::back(t);
	}
	if (son[x]) dfs2(son[x],x);
	dsu::connect(c[x],d[x]);
	for (int i=first[x];i!=-1;i=nxt[i])
	{
		int u=point[i];
		if (u==fa || u==son[x]) continue;
		dfs1(u,x);
	}
	ans[x]=cnt;
}
signed main()
{
	tot=-1;
	memset(first,-1,sizeof(first));
	memset(nxt,-1,sizeof(nxt));
	scanf("%d%d",&n,&k);
	for (int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add_edge(u,v);
		add_edge(v,u);
	}
	for (int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
	dfs(1,1);
	dsu::init();
	dfs2(1,1);
	for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
accuracy: 0.15789473684210525
time_ms: 40
memory_kb: 15972
final_rank: 17

code_snippet: #include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define fi first
#define se second
#define kill _z_kill
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define outval(x) cerr<<#x" = "<<x<<endl
#define outv(x) cerr<<#x" = "<<x<<"  "
#define outtag(x) cerr<<"--------------"#x"---------------"<<endl
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
	For(_x,L,R) cerr<<a[_x]<<" ";cerr<<endl;
#define User_Time ((double)clock()/CLOCKS_PER_SEC)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned uint;
typedef long double LD;
typedef vector <int> vi;
typedef pair <int,int> pii;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
//int Pow(int x,int y){
//	int ans=1;
//	for (;y;y>>=1,x=(LL)x*x%mod)
//		if (y&1)
//			ans=(LL)ans*x%mod;
//	return ans;
//}
//void Add(int &x,int y){
//	if ((x+=y)>=mod)
//		x-=mod;
//}
//void Del(int &x,int y){
//	if ((x-=y)<0)
//		x+=mod;
//}
//int Add(int x){
//	return x>=mod?x-mod:x;
//}
//int Del(int x){
//	return x<0?x+mod:x;
//}
//void ckmax(int &x,int y){
//	if (x<y)
//		x=y;
//}
//void ckmin(int &x,int y){
//	if (x>y)
//		x=y;
//}
const int N=100005;
int n,k;
vi e[N],id[N];
int sz[N],son[N];
int a[N],b[N];
int ans[N];
void dfs(int x,int pre){
	sz[x]=1;
	for (auto y : e[x]){
		if (y==pre)
			continue;
		dfs(y,x);
		sz[x]+=sz[y];
		if (!son[x]||sz[y]>sz[son[x]])
			son[x]=y;
	}
}
int fa[N],c[N],sc[N];
int getf(int x){
	return fa[x]==x?x:fa[x]=getf(fa[x]);
}
int fuck(int x){
	assert(c[x]>=sc[x]-1);
	return min(c[x],sc[x]);
}
void init(int z){
	fa[z]=z,sc[z]=1,c[z]=0;
}
void adde(int i,int x,int y){
	int fx=getf(x),fy=getf(y);
//	outval(fx),outval(fy);
//	outval(fuck(fx)),outval(fuck(fy));
	ans[i]-=fuck(fx);
	if (fx!=fy){
		ans[i]-=fuck(fy);
		fa[fy]=fx;
		c[fx]+=c[fy];
		sc[fx]+=sc[fy];
	}
	c[fx]++;
//	outval(fuck(fx));
	ans[i]+=fuck(fx);
}
void solve(int x,int pre){
	for (auto y : e[x])
		if (y!=pre&&y!=son[x]){
			solve(y,x);
			for (auto z : id[y]){
				init(a[z]);
				init(b[z]);
			}
		}
	int y=son[x];
	if (y){
		solve(y,x);
		ans[x]=ans[y];
		swap(id[x],id[y]);
	}
	id[x].pb(x);
	adde(x,a[x],b[x]);
	for (auto y : e[x])
		if (y!=pre&&y!=son[x]){
			for (auto z : id[y]){
				id[x].pb(z);
				adde(x,a[z],b[z]);
			}
		}
}
int main(){
	n=read(),k=read();
	For(i,1,n-1){
		int x=read(),y=read();
		e[x].pb(y),e[y].pb(x);
	}
	For(i,1,n)
		a[i]=read(),b[i]=read();
	For(i,1,k)
		sc[i]=1,fa[i]=i;
	dfs(1,0);
	solve(1,0);
	For(i,1,n)
		printf("%d\n",ans[i]);
	return 0;
}
accuracy: 0.14035087719298245
time_ms: 20
memory_kb: 14952
final_rank: 19

code_snippet: #include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<vector>
#include<functional>
using namespace std;
typedef long long LL;
inline long long read()
{
	long long kk=0,f=1;
	char cc=getchar();
	while(cc<'0'||cc>'9'){if(cc=='-')f=-1;cc=getchar();}
	while(cc>='0'&&cc<='9'){kk=(kk<<1)+(kk<<3)+cc-'0';cc=getchar();}
	return kk*f;
}
set<int>node;
vector<int>edge[55],point[55];
int x[55],y[55];
int n,k;
void add(int a,int b)
{
	edge[a].push_back(b);
	edge[b].push_back(a);
}
void dfs(int now,int fa)
{
	point[now].push_back(now);
	for(int i=0;i<edge[now].size();++i)
	{
		int to=edge[now][i];
		if(to!=fa)
		{
			dfs(to,now);
			for(int k=0;k<point[to].size();++k)
			point[now].push_back(point[to][k]);
		}
	}
}
void dfs2(int &ans,int now,int fr)
{
	if(ans<node.size())ans=node.size();
	for(int i=fr;i<point[now].size();++i)
	{
		if(ans<node.size())ans=node.size();
		int to=point[now][i];
		if(node.count(x[to]))node.insert(y[to]);
		else if(node.count(y[to]))node.insert(x[to]);
		else
		{
			set<int>lin;lin.clear();
			lin.insert(node.begin(),node.end());
			node.insert(y[to]);
			if(ans<node.size())ans=node.size();
			dfs2(ans,now,i+1);
			node.clear();
			node.insert(lin.begin(),lin.end());
			node.insert(x[to]);
			if(ans<node.size())ans=node.size();
		}
	}
	if(ans<node.size())ans=node.size();
}
int main()
{
	n=read();k=read();
	for(int i=1;i<n;++i)add(read(),read());
	for(int i=1;i<=n;++i)
	{
		x[i]=read();y[i]=read();
	}
	dfs(1,0);
	for(int i=1;i<=n;++i)
	{
		node.clear();
		int ans=0;
		dfs2(ans,i,0);
		printf("%d\n",ans);
	}
}
accuracy: 0.08771929824561403
time_ms: 40
memory_kb: 3572
final_rank: 20

code_snippet: /*
考虑整棵树，每个点选 ci 还是 di，这跟“树”这个结构没有关系，
就是一个经典问题：一个 n 个点 m 条边的图，每条边连接 ci 和 di，可以染黑 ci 或 di，问最大黑点数
显然是 min{|V|, |E|}：首先最多有 |V| 个，其次如果边为 V - 1（是树）那就是 V - 1
min{|V|, |E|} = |V| - 1 + [是否存在非树边]，并查集维护就好了。

对于每个子树：dsu on tree。考虑到 有删除操作，用可撤销并查集维护。
*/
#include <bits/stdc++.h>
#define rep(i, x, y) for (int i = x; i <= y; i++)
#define int long long
using namespace std;

const int N = 5e5 + 10;
typedef long long ll;
ll n, K, tot, top;
ll sz[N], son[N], fa[N], siz[N];
ll c[N], d[N], ans[N], cnt[N], stk[N];
vector<int> nxt[N];

int getfa(int x) {
    return fa[x] == x ? x : getfa(fa[x]);
}

void merge(int x, int y) {
    x = getfa(x), y = getfa(y);
    if (x == y) {
        if (!cnt[x]) ++tot;
        cnt[x]++;
        stk[++top] = -x;
    } else {
        if (siz[x] > siz[y]) swap(x, y);
        if (!cnt[x] || !cnt[y]) ++tot;
        cnt[y] += cnt[x];
        fa[x] = y;
        siz[y] += siz[x];
        stk[++top] = x;
    }
}

void eras(int x) {
    while (top > x) {
        int t = stk[top--];
        if (t < 0) {
            --cnt[-t];
            if (!cnt[-t]) --tot;
        } else {
            cnt[fa[t]] -= cnt[t];
            siz[fa[t]] -= siz[t];
            if (!cnt[x] || !cnt[fa[t]]) --tot;
            fa[t] = t;
        }
    }
}

void calc(int x, int fa) {
    merge(c[x], d[x]);
    for (int i = 0; i < nxt[x].size(); i++) {
        int y = nxt[x][i];
        if (y != fa) calc(y, x);
    }
}

void dfs1(int x, int fa) {
    sz[x] = 1;
    for (int i = 0; i < nxt[x].size(); i++) {
        int y = nxt[x][i];
        if (y == fa) continue;
        dfs1(y, x);
        sz[x] += sz[y];
        if (sz[y] > sz[son[x]]) son[x] = y;
    }
}

void dfs2(int x, int fa) {
    for (int i = 0; i < nxt[x].size(); i++) {
        int y = nxt[x][i];
        if (y != son[x] && y != fa) {
            int pos = top;
            dfs2(y, x);
            eras(pos);
        }
    }
    if (son[x]) dfs2(son[x], x);
    merge(c[x], d[x]);
    for (int i = 0; i < nxt[x].size(); i++) {
        int y = nxt[x][i];
        if (y != son[x] && y != fa) {
            calc(y, x);
        }
    }
    ans[x] = tot;
}

signed main() {
    cin >> n >> K;
    rep(i, 1, K) fa[i] = i, siz[i] = 1;
    rep(i, 1, n - 1) {
        int x, y; scanf("%lld%lld", &x, &y);
        nxt[x].push_back(y), nxt[y].push_back(x);
    }
    rep(i, 1, n) scanf("%lld%lld", &c[i], &d[i]);
    dfs1(1, 0);
    dfs2(1, 0);
    rep(i, 1, n) printf("%lld\n", ans[i]);
    return 0;
}
accuracy: 0.15789473684210525
time_ms: 50
memory_kb: 41400
final_rank: 18

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;

using ll = long long;
#define rep(i,n) for(ll i=0; i<ll(n); i++)

struct Dsu {
    Dsu(int n) : A(n,-1), H(n,0), V(), hsum(0) {}
    int leader(int x){
        if(A[x] < 0) return x;
        return A[x] = leader(A[x]);
    }
    void merge(int u, int v){
        u = leader(u); v = leader(v);
        if(u != v){
            if(-A[u] < -A[v]) swap(u,v);
            A[u] += A[v]; H[u] += H[v];
            A[v] = u;
            V.push_back(u);
            V.push_back(v);
        } else V.push_back(u);
        if(H[u] < -A[u]){ H[u]++; hsum++; }
    }
    void reset(){
        for(int v : V){
            A[v] = -1;
            H[v] = 0;
        }
        V = {};
        hsum = 0;
    }
    vector<int> A, H, V;
    int hsum;
};

void testcase(){
    int N, K; cin >> N >> K;
    vector<vector<int>> adj(N);
    rep(i,N-1){
        int u,v; cin >> u >> v; u--; v--;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    vector<int> U(N), V(N);
    rep(i,N) cin >> U[i] >> V[i];
    Dsu dsu(K+1);

    vector<int> par(N,-1), bfs, sz(N,1);
    bfs.push_back(0);
    rep(i,bfs.size()){
        int v = bfs[i];
        for(int w : adj[v]) if(par[v] != w){
            par[w] = v;
            bfs.push_back(w);
        }
    }
    for(int i=N-1; i>=1; i--) sz[par[bfs[i]]] += sz[bfs[i]];

    vector<int> ans(N);
    auto dfs = [&](auto& dfs, int n, int v) -> void {
        if(n){
            int he = -1;
            for(int w : adj[v]) if(par[v] != w){
                if(he == -1 || sz[he] < sz[w]) he = w;
            }
            for(int w : adj[v]) if(par[v] != w && he != w){
                dfs(dfs, 1, w); dsu.reset();
            }
            if(he != -1) dfs(dfs, 1, he);
            for(int w : adj[v]) if(par[v] != w && he != w){
                dfs(dfs, 0, w);
            }
            dsu.merge(U[v], V[v]);
            ans[v] = dsu.hsum;
        } else {
            for(int w : adj[v]) if(par[v] != w) dfs(dfs, 0, w);
            dsu.merge(U[v], V[v]);
        }
    };
    dfs(dfs, 1, 0);
    rep(i,N) cout << ans[i] << "\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    testcase();
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 24340
final_rank: 1

code_snippet: /*
#pragma GCC optimize("Ofast")
#pragma GCC target("avx2")
#pragma GCC optimize("unroll-loops")
//*/
/*
#ifndef LOCAL
#pragma GCC target("avx512f,avx512dq,avx512cd,avx512bw,avx512vl")
#endif
//*/
#define _USE_MATH_DEFINES
#define _EXT_CODECVT_SPECIALIZATIONS_H 1
#define _EXT_ENC_FILEBUF_H 1
#if __has_include(<x86intrin.h>) && defined(__x86_64__)
#include <x86intrin.h>
#endif
#include <bits/stdc++.h>
using namespace std;
/*
#include <atcoder/all>
using namespace atcoder;
//*/
/*
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using bll = boost::multiprecision::cpp_int;
using bdouble = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100>>;
using namespace boost::multiprecision;
/*/
using bll = __int128_t;
#if __has_include(<quadmath.h>)
#include <quadmath.h>
using bdouble = __float128;
#else
using bdouble = long double;
#endif
namespace std {
	__int128_t parse_int128(const string &s) { __int128_t r = 0; for (auto c : s) { if ('0' <= c && c <= '9') r = 10 * r + c - '0'; } if (s.size() && s[0] == '-') r = -r; return r; }
	template <typename T, typename std::enable_if_t<std::is_same_v<T, __int128_t> || std::is_same_v<T, __uint128_t>, std::nullptr_t> = nullptr> std::string to_string(T n) { if (n == 0) return "0"; bool minus = n < 0; if (minus) n = -n; std::string r; while (n > 0) r += '0' + n % 10, n /= 10; if (minus) r += '-'; reverse(r.begin(), r.end()); return r; }
	template <typename T, typename std::enable_if_t<std::is_same_v<T, __int128_t> || std::is_same_v<T, __uint128_t>, std::nullptr_t> = nullptr> std::istream& operator>>(std::istream& s, T& n) { std::string t; s >> t; n = parse_int128(t); return s; }
	template <typename T, typename std::enable_if_t<std::is_same_v<T, __int128_t> || std::is_same_v<T, __uint128_t>, std::nullptr_t> = nullptr> std::ostream& operator<<(std::ostream& s, const T& n) { return s << to_string(n); }
#ifdef __clang__
	template <typename T, typename std::enable_if_t<std::is_same_v<T, __int128_t> || std::is_same_v<T, __uint128_t>, std::nullptr_t> = nullptr> T abs(T x) { return x >= 0 ? x : -x; }
#endif
#if __has_include(<quadmath.h>)
#ifdef LOCAL
	__float128 parse_float128(const string &s) { return strtoflt128(s.c_str(), nullptr); }
	std::string to_string(__float128 n, int precision = 20) { char buf[128]; quadmath_snprintf(buf, sizeof(buf), "%.*Qf", precision, n); return std::string(buf); }
#else
	__float128 parse_float128(const string &s) { return static_cast<__float128>(std::stold(s)); }
	std::string to_string(__float128 n, [[maybe_unused]] int precision = 20) { return std::to_string(static_cast<long double>(n)); }
#endif
	std::istream& operator>>(std::istream& s, __float128& n) { std::string t; s >> t; n = parse_float128(t); return s; }
	std::ostream& operator<<(std::ostream& s, const __float128& n) { return s << to_string(n); }
#endif
}
//*/
#define ENV_USE_FASTIO 1
#define ENV_USE_BACKSLASH_N 1
#define ENV_USE_DETERMINISTIC 1
#if !defined(LOCAL_DEV) && ENV_USE_FASTIO
	#define USE_FASTIO
#endif
#if ENV_USE_BACKSLASH_N
	#define NEWLINE '\n'
#else
	#define NEWLINE std::endl
#endif
//#define int long long
using ll = long long;
using ld = long double;
std::vector<std::string> ARGV;
//constexpr ll MOD = (ll)1e9 + 7; //primitive root = 5
constexpr ll MOD = 998244353; //primitive root = 3
//INT_MAX = (1<<31)-1 = 2147483647, INT64_MAX = (1LL<<63)-1 = 9223372036854775807
constexpr ll INF = std::numeric_limits<ll>::max() == INT_MAX ? (ll)1e9 + 7 : (ll)2e18 + 1;
constexpr double EPS = 1e-9;
constexpr std::array<int, 4> dx = {0, -1, 0, 1}; //['R', 'U', 'L', 'D']
constexpr std::array<int, 4> dy = {1, 0, -1, 0};
constexpr std::array<int, 8> dx8 = {0, -1, -1, -1, 0, 1, 1, 1};
constexpr std::array<int, 8> dy8 = {1, 1, 0, -1, -1, -1, 0, 1};

#ifdef LOCAL
	#define BOOST_STACKTRACE_USE_ADDR2LINE
	#define BOOST_STACKTRACE_ADDR2LINE_LOCATION /usr/local/opt/binutils/bin/addr2line
	#ifndef _GNU_SOURCE
	#define _GNU_SOURCE
	#endif
	#include <boost/stacktrace.hpp>
#else
	namespace boost::stacktrace { std::string stacktrace() { return ""; } }
#endif
#if __has_include("cpp-dump-mysettings.hpp") && defined(LOCAL_DEV)
	#include "cpp-dump-mysettings.hpp"
#else
	#define debug(...) do {} while (false)
	#define debugr(...) do {} while (false)
	#define debugy(...) do {} while (false)
#endif
#ifdef LOCAL_DEV
	constexpr inline long long prodlocal(long long, long long local) { return local; }
#else
	constexpr inline long long prodlocal(long long prod, long long) { return prod; }
#endif
#ifdef LOCAL_TEST
	namespace std {
		template <typename T> class dvector : public std::vector<T> {
		public:
			using std::vector<T>::vector;
			void throw_out_of_range(size_t n) const {
				std::cerr << boost::stacktrace::stacktrace() << std::endl; throw std::out_of_range((std::ostringstream() << "vector::_M_range_check: __n (which is " << n << ") >= this->size() (which is " << this->size() << ")").str());
			}
			template <typename T_ = T, typename std::enable_if_t<std::is_same_v<T_, bool>, std::nullptr_t> = nullptr> std::vector<bool>::reference operator[](size_t n) {
				if (this->size() <= n) { throw_out_of_range(n); } return this->at(n);
			}
			template <typename T_ = T, typename std::enable_if_t<std::is_same_v<T_, bool>, std::nullptr_t> = nullptr> const T_ operator[](size_t n) const {
				if (this->size() <= n) { throw_out_of_range(n); } return this->at(n);
			}
			template <typename T_ = T, typename std::enable_if_t<!std::is_same_v<T_, bool>, std::nullptr_t> = nullptr> constexpr T_& operator[](size_t n) {
				if (this->size() <= n) { throw_out_of_range(n); } return this->at(n);
			}
			template <typename T_ = T, typename std::enable_if_t<!std::is_same_v<T_, bool>, std::nullptr_t> = nullptr> constexpr const T_& operator[](size_t n) const {
				if (this->size() <= n) { throw_out_of_range(n); } return this->at(n);
			}
		};
		template <typename T, size_t N> class darray : public std::array<T, N> {
		public:
			using std::array<T, N>::array;
			constexpr darray(std::initializer_list<T> il) {
				*this = {}; int i = 0; for (auto&& x : il) this->operator[](i++) = x;
			}
			void throw_out_of_range(size_t n) const {
				std::cerr << boost::stacktrace::stacktrace() << std::endl; throw std::out_of_range((std::ostringstream() << "array::at: __n (which is " << n << ") >= _Nm (which is " << this->size() << ")").str());
			}
			constexpr T& operator[](size_t n) {
				if (this->size() <= n) { throw_out_of_range(n); } return this->at(n);
			}
			constexpr const T& operator[](size_t n) const {
				if (this->size() <= n) { throw_out_of_range(n); } return this->at(n);
			}
		};
		template <typename T, size_t N> struct tuple_size<std::darray<T, N>> : integral_constant<size_t, N> {};
		template <typename T, size_t N, size_t I> struct tuple_element<I, std::darray<T, N>> { using type = T; };
		template <typename T, typename Compare = std::less<T>> class dmultiset : public std::multiset<T, Compare> {
		public:
			using std::multiset<T, Compare>::multiset;
			const typename std::multiset<T, Compare>::iterator erase(const typename std::multiset<T, Compare>::iterator it) {
				return std::multiset<T, Compare>::erase(it);
			}
			size_t erase([[maybe_unused]] const T& x) {
				std::cerr << boost::stacktrace::stacktrace() << '\n'; throw std::exception();
			}
			size_t erase_all_elements(const T& x) {
				return std::multiset<T, Compare>::erase(x);
			}
		};
		template <typename T> std::ostream& operator<<(std::ostream& s, const std::set<T>& se) { s << "{ "; for (auto it = se.begin(); it != se.end(); ++it){ s << *it << "\t"; } s << "}"; return s; }
		template <typename T> std::ostream& operator<<(std::ostream& s, const std::unordered_set<T>& se) { s << "{ "; for (auto it = se.begin(); it != se.end(); ++it){ s << *it << "\t"; } s << "}"; return s; }
		template <typename T> std::ostream& operator<<(std::ostream& s, const std::multiset<T>& se) { s << "{ "; for (auto it = se.begin(); it != se.end(); ++it){ s << *it << "\t"; } s << "}"; return s; }
		template <typename T> std::ostream& operator<<(std::ostream& s, const std::deque<T>& v) { s << "{ "; for (size_t i = 0; i < v.size(); ++i){ s << v[i] << "\t"; } s << "}"; return s; }
		template <typename T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v) { s << "{ "; for (size_t i = 0; i < v.size(); ++i){ s << v[i] << "\t"; } s << "}"; return s; }
		template <typename T> std::ostream& operator<<(std::ostream& s, const std::vector<std::dvector<T>>& vv) { s << "\\\n"; for (size_t i = 0; i < vv.size(); ++i){ s << vv[i] << (i + 1 == vv.size() ? "" : "\n"); } return s; }
		template <typename T1, typename T2> std::ostream& operator<<(std::ostream& s, const std::pair<T1, T2>& p) { return s << "(" << p.first << ", " << p.second << ")"; }
		template <typename T1, typename T2> std::ostream& operator<<(std::ostream& s, const std::map<T1, T2>& m) { s << "{\n"; for (auto it = m.begin(); it != m.end(); ++it){ s << "\t" << it->first << " : " << it->second << "\n"; } s << "}"; return s; }
		template <typename T1, typename T2> std::ostream& operator<<(std::ostream& s, const std::unordered_map<T1, T2>& m) { s << "{\n"; for (auto it = m.begin(); it != m.end(); ++it){ s << "\t" << it->first << " : " << it->second << "\n"; } s << "}"; return s; }
		template <typename T, size_t N> std::ostream& operator<<(std::ostream& s, const std::array<T, N>& v) { s << "{ "; for (size_t i = 0; i < N; ++i){ s << v[i] << "\t"; } s << "}"; return s; }
		template <typename T, size_t N, size_t M> std::ostream& operator<<(std::ostream& s, const std::array<std::darray<T, M>, N>& vv) { s << "\\\n"; for (size_t i = 0; i < vv.size(); ++i){ s << vv[i] << (i + 1 == vv.size() ? "" : "\n"); } return s; }
		template <typename T, size_t N, typename std::enable_if_t<!std::is_same_v<T, char> && !std::is_same_v<T, const char>, std::nullptr_t> = nullptr> std::ostream& operator<<(std::ostream& s, const T (&v)[N]) { s << "{ "; for (size_t i = 0; i < N; ++i){ s << v[i] << "\t"; } s << "}"; return s; }
		template <typename T, size_t N, size_t M, typename std::enable_if_t<!std::is_same_v<T, char> && !std::is_same_v<T, const char>, std::nullptr_t> = nullptr> std::ostream& operator<<(std::ostream& s, const T (&vv)[N][M]) { s << "\\\n"; for (size_t i = 0; i < N; ++i){ s << vv[i] << (i + 1 == N ? "" : "\n"); } return s; }
		std::ostream& operator<<(std::ostream& s, const std::vector<std::string>& v) { s << "\\\n"; for (size_t i = 0; i < v.size(); ++i){ s << v[i] << (i + 1 == v.size() ? "" : "\n"); } return s; }
		template <typename Tuple, size_t... Is> void print_tuple(std::ostream& os, const Tuple& t, std::index_sequence<Is...>) { ((os << std::get<Is>(t) << '\t'), ...); }
		template <typename... Tp> std::ostream& operator<<(std::ostream& s, const std::tuple<Tp...>& t) { s << "{ "; print_tuple(s, t, std::index_sequence_for<Tp...>{}); s << '}'; return s; }
	} // namespace std
	#define vector dvector
	#define array darray
	#define multiset dmultiset
	void catch_SIGABRT(int e) { std::cerr << boost::stacktrace::stacktrace() << "\nSIGABRT signal received." << std::endl; std::exit(e); }
	void catch_SIGFPE(int e) { std::cerr << boost::stacktrace::stacktrace() << "\nSIGFPE signal received." << std::endl; std::exit(e); }
	void catch_SIGSEGV(int e) { std::cerr << boost::stacktrace::stacktrace() << "\nSIGSEGV signal received." << std::endl; std::exit(e); }
	signed convertedmain(int argc, char *argv[]);
	signed main(int argc, char *argv[]) { signal(SIGABRT, catch_SIGABRT); signal(SIGFPE, catch_SIGFPE); signal(SIGSEGV, catch_SIGSEGV); return convertedmain(argc, argv); }
	#define main(argc, argv) convertedmain(argc, argv)
#else
	#define erase_all_elements erase
#endif
#define overload4(_1, _2, _3, _4, name, ...) name
#define rep4(i, a, b, c) for(ll i=(a), i##_length=(b); i<i##_length; i+=(c))
#define rep3(i, a, b) rep4(i, a, b, 1)
#define rep2(i, n) rep4(i, 0, n, 1)
#define rep1(n) rep4(i, 0, n, 1)
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define repeq4(i, a, b, c) rep4(i, (a)+1, (b)+1, c)
#define repeq3(i, a, b) rep4(i, (a)+1, (b)+1, 1)
#define repeq2(i, n) rep4(i, 1, (n)+1, 1)
#define repeq1(n) rep4(i, 1, (n)+1, 1)
#define repeq(...) overload4(__VA_ARGS__, repeq4, repeq3, repeq2, repeq1)(__VA_ARGS__)
#define rrep4(i, a, b, c) for(ll i=(b)-1; i>=(a); i-=(c))
#define rrep3(i, a, b) rrep4(i, a, b, 1)
#define rrep2(i, n) rrep4(i, 0, n, 1)
#define rrep1(n) rrep4(i, 0, n, 1)
#define rrep(...) overload4(__VA_ARGS__, rrep4, rrep3, rrep2, rrep1)(__VA_ARGS__)
#define rrepeq4(i, a, b, c) rrep4(i, (a)+1, (b)+1, c)
#define rrepeq3(i, a, b) rrep4(i, (a)+1, (b)+1, 1)
#define rrepeq2(i, n) rrep4(i, 1, (n)+1, 1)
#define rrepeq1(n) rrep4(i, 1, (n)+1, 1)
#define rrepeq(...) overload4(__VA_ARGS__, rrepeq4, rrepeq3, rrepeq2, rrepeq1)(__VA_ARGS__)
#define all(v) std::begin(v), std::end(v)
#define rall(v) std::rbegin(v), std::rend(v)
template <typename T> using priority_queue_rev = std::priority_queue<T, std::vector<T>, std::greater<T>>;
void p() { std::cout << NEWLINE; }
template <typename Head, typename... Tail> void p(Head& head, Tail&... tail) { std::cout << head << (sizeof...(Tail) ? " " : ""); p(tail...); }
template <typename Head, typename... Tail> void p(const Head& head, const Tail&... tail) { std::cout << head << (sizeof...(Tail) ? " " : ""); p(tail...); }
template <typename T> inline void pv(const T& v) { auto itbegin = std::begin(v), itend = std::end(v); for (auto it = itbegin; it != itend; std::advance(it, 1)) std::cout << (it == itbegin ? "" : " ") << *it; std::cout << NEWLINE; }
template <typename T, typename U = typename T::value_type> inline void pv(const T& v, const U& add) { auto itbegin = std::begin(v), itend = std::end(v); for (auto it = itbegin; it != itend; std::advance(it, 1)) std::cout << (it == itbegin ? "" : " ") << *it + add; std::cout << NEWLINE; }
template <typename T> inline bool chmax(T& a, T b) { return a < b && (a = b, true); }
template <typename T> inline bool chmin(T& a, T b) { return a > b && (a = b, true); }
template <typename T> inline void uniq(T& v) { std::sort(v.begin(), v.end()); v.erase(std::unique(v.begin(), v.end()), v.end()); }
template <typename T> inline int sz(const T& v) { return std::size(v); }
template <typename T> inline T floor(T a, T b) { return a / b - ((a ^ b) < 0 && a % b); }
template <typename T> inline T ceil(T a, T b) { return floor(a + b - 1, b); }
template <typename T, size_t N> std::vector<T> make_vector_impl(std::vector<ll>& sizes, typename std::enable_if<(N == 1), const T&>::type x) { return std::vector<T>(sizes.front(), x); }
template <typename T, size_t N> auto make_vector_impl(std::vector<ll>& sizes, typename std::enable_if<(N > 1), const T&>::type x) { ll size = sizes.back(); sizes.pop_back(); return std::vector<decltype(make_vector_impl<T, N - 1>(sizes, x))>(size, make_vector_impl<T, N - 1>(sizes, x)); }
template <typename T, size_t N> auto make_vector(const ll (&sizes)[N], const T& x = T()) { std::vector<ll> s(std::rbegin(sizes), std::rend(sizes)); return make_vector_impl<T, N>(s, x); }
template <typename T, size_t N> std::array<T, N> make_array() { return std::array<T, N>{}; }
template <typename T, size_t Head, size_t... Tail, typename std::enable_if_t<(sizeof...(Tail) >= 1), std::nullptr_t> = nullptr> auto make_array() { return std::array<decltype(make_array<T, Tail...>()), Head>(); }
template <typename T, typename F> std::pair<T, T> nibutan(T left, T right, const F& f) { while (std::abs(right - left) > 1) { T mid = left + (right - left) / 2; (f(mid) ? left : right) = mid; } return {left, right}; }
template <typename T, typename F> std::pair<T, T> nibutan_double(T threshold, T left, T right, const F& f) { int c = static_cast<int>(log2(abs(right - left) / threshold)) + 3; while (abs(right - left) > threshold && c--) { T mid = left + (right - left) / 2; (f(mid) ? left : right) = mid; } return {left, right}; }
template <bool Index, typename... T> class zip_helper {
	template <class Category, class Type, class Diff = ptrdiff_t, class Ptr = Type*, class Ref = Type&> struct basic_iterator {
		using difference_type = Diff;
		using value_type = Type;
		using pointer = Ptr;
		using reference = Ref;
		using iterator_category = Category;
	};
	struct zip_iterator : public basic_iterator<std::forward_iterator_tag, std::tuple<decltype(*std::declval<T>().begin())...>> {
		int idx_;
		std::tuple<decltype(std::declval<T>().begin())...> iters_;
		template <size_t... I> auto deref(std::index_sequence<I...>) const { return typename zip_iterator::value_type{*std::get<I>(iters_)...}; }
		template <size_t... I> void increment(std::index_sequence<I...>) { [[maybe_unused]] auto l = {(++std::get<I>(iters_), 0)...}; }
		explicit zip_iterator(decltype(iters_) iters) : idx_(0), iters_{std::move(iters)} {}
		zip_iterator& operator++() { ++idx_; increment(std::index_sequence_for<T...>{}); return *this; }
		zip_iterator operator++(int) { auto saved{*this}; ++idx_; increment(std::index_sequence_for<T...>{}); return saved; }
		bool operator!=(const zip_iterator& other) const { return iters_ != other.iters_; }
		template <bool Index_ = Index, typename std::enable_if_t<Index_, std::nullptr_t> = nullptr> auto operator*() const { return std::tuple_cat(std::make_tuple(this->idx_), this->deref(std::index_sequence_for<T...>{})); }
		template <bool Index_ = Index, typename std::enable_if_t<!Index_, std::nullptr_t> = nullptr> auto operator*() const { return this->deref(std::index_sequence_for<T...>{}); }
	};
	zip_iterator begin_, end_;
public:
	zip_helper(T&... seqs) : begin_{std::make_tuple(seqs.begin()...)}, end_{std::make_tuple(seqs.end()...)} {}
	zip_iterator begin() const { return begin_; }
	zip_iterator end() const { return end_; }
};
template <typename... T> auto zip(T&&... seqs) { return zip_helper<false, T...>{seqs...}; }
template <typename... T> auto zipindex(T&&... seqs) { return zip_helper<true, T...>{seqs...}; }
template <typename T1, typename T2> class pairr : public std::pair<T1, T2> {
	struct x { x(int n) { assert(n == 1); } };
public:
	using std::pair<T1, T2>::pair;
	T1& operator[](nullptr_t) { return this->first; }
	const T1& operator[](nullptr_t) const { return this->first; }
	T2& operator[](x) { return this->second; }
	const T2& operator[](x) const { return this->second; }
};
struct custom_hash {
	constexpr static uint64_t splitmix64(uint64_t x) {
		x += 0x9e3779b97f4a7c15, x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9, x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31);
	}
	template <typename T> size_t combine_hash(size_t seed, const T& value) const {
		return seed ^ (operator()(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
	};
	size_t operator()(uint64_t x) const {
#if ENV_USE_DETERMINISTIC
		return splitmix64(x);
#else
		static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM);
#endif
	}
	template <typename T1, typename T2>	size_t operator()(const std::pair<T1, T2>& x) const {
		size_t h = operator()(x.first); return combine_hash(h, operator()(x.second));
	}
	template <typename... Tp> size_t operator()(const std::tuple<Tp...>& t) const {
		size_t h = std::tuple_size<std::tuple<Tp...>>::value; std::apply([&](const auto&... k) { (..., (h = combine_hash(h, k))); }, t); return h;
	}
	template <typename C, typename T = std::decay_t<decltype(*begin(std::declval<C>()))>> size_t operator()(const C& container) const {
		size_t h = container.size(); for (auto&& k : container) h = combine_hash(h, k); return h;
	}
};
#if __has_include(<ext/pb_ds/assoc_container.hpp>)
#include <bits/extc++.h>
template <typename Key, typename T, typename Hash = custom_hash> using fmapbase = __gnu_pbds::gp_hash_table<Key, T, Hash, std::equal_to<Key>, __gnu_pbds::direct_mask_range_hashing<>, __gnu_pbds::linear_probe_fn<>, __gnu_pbds::hash_standard_resize_policy<__gnu_pbds::hash_exponential_size_policy<>, __gnu_pbds::hash_load_check_resize_trigger<>, true>>;
template <typename Key, typename T, typename Hash = custom_hash> class fmap : public fmapbase <Key, T, Hash> {
public:
	using fmapbase<Key, T, Hash>::gp_hash_table;
	template <typename T_ = T, typename std::enable_if_t<std::is_same_v<T_, __gnu_pbds::null_type>, std::nullptr_t> = nullptr> fmap(std::initializer_list<Key> il) : fmapbase<Key, T, Hash>(il.begin(), il.end()) {}
	template <typename T_ = T, typename std::enable_if_t<!std::is_same_v<T_, __gnu_pbds::null_type>, std::nullptr_t> = nullptr> fmap(std::initializer_list<std::pair<Key, T>> il) : fmapbase<Key, T, Hash>(il.begin(), il.end()) {}
	void reserve(size_t n) {
		fmapbase<Key, T, Hash>::resize(n);
	}
	int count(const Key& x) const {
		return fmapbase<Key, T, Hash>::find(x) != fmapbase<Key, T, Hash>::end();
	}
	template <typename K> int count(const K& x) const {
		return fmapbase<Key, T, Hash>::find(x) != fmapbase<Key, T, Hash>::end();
	}
};
template <typename Key, typename Hash = custom_hash> using fset = fmap<Key, __gnu_pbds::null_type, Hash>;
#ifdef LOCAL_TEST
template <typename Key, typename T, typename Hash> std::ostream& operator<<(std::ostream& s, const fmapbase<Key, T, Hash>& m) { s << "{\n"; for (auto it = m.begin(); it != m.end(); ++it){ s << "\t" << it->first << " : " << it->second << "\n"; } s << "}"; return s; }
template <typename Key, typename Hash> std::ostream& operator<<(std::ostream& s, const fmapbase<Key, __gnu_pbds::null_type, Hash>& se) { s << "{ "; for (auto it = se.begin(); it != se.end(); ++it){ s << *it << "\t"; } s << "}"; return s; }
#endif
#else
template <typename Key, typename T, typename Hash = custom_hash> using fmap = std::unordered_map<Key, T, Hash>;
template <typename Key, typename Hash = custom_hash> using fset = std::unordered_set<Key, Hash>;
#endif

/*-----8<-----template-----8<-----*/

class UnionFindDynamic {
	int data(int k) {
		auto it = v.find(k);
		return it == v.end() ? v[k] = -1 : it->second;
	}
	int linkdata(int k) const {
		auto it = v.find(k);
		return it == v.end() ? k : it->second;
	}

public:
	fmap<int, int> v, link;
	UnionFindDynamic() = default;

	int root(int k) {
		int n = data(k);
		return n < 0 ? k : v[k] = root(n);
	}

	int unite(int x, int y) {
		x = root(x), y = root(y);
		if (x == y) return false;
		auto itx = v.find(x), ity = v.find(y);
		if (itx->second > ity->second) swap(itx, ity), swap(x, y);
		itx->second += ity->second;
		ity->second = x;
		return true;
	}

	int size(int k) {
		return -data(root(k));
	}

	int is_same(int x, int y) {
		return root(x) == root(y);
	}
	
    void clear() {
        v.clear();
        link.clear();
	}

	// Get items connected to `x` (including `x`). Let the size of return value be `m`, time complexity is O(m).
	vector<ll> connected_component(int x) const {
		vector<ll> comp{x};
		for (int y = linkdata(x); y != x; y = linkdata(y)) comp.push_back(y);
		return comp;
	}
};
std::ostream& operator<<(std::ostream& s, const UnionFindDynamic& uf) {
    s << "{\n"; for (auto it = uf.v.begin(); it != uf.v.end(); ++it){ s << "\t" << it->first << " : " << it->second << "\n"; } s << "}"; return s;
}

//[lib]DSUonTree.cpp
// https://nyaannyaan.github.io/library/tree/dsu-on-tree.hpp.html
// https://speakerdeck.com/camypaper/dsu-on-tree
template <typename G>
class DSUonTree {
private:
	G &g;
	int N;
	vector<int> sub_sz, euler, down, up;
	int idx_;
	int root;

	int dfs1(int cur, int par = -1) {
		sub_sz[cur] = 1;
		if ((int)g[cur].size() >= 2 and g[cur][0] == par) {
			swap(g[cur][0], g[cur][1]);
		}
		for (auto &dst : g[cur]) {
			if (dst == par) continue;
			sub_sz[cur] += dfs1(dst, cur);
			if (sub_sz[dst] > sub_sz[g[cur][0]]) swap(dst, g[cur][0]);
		}
		return sub_sz[cur];
	}

	void dfs2(int cur, int par = -1) {
		euler[idx_] = cur;
		down[cur] = idx_++;
		for (auto &dst : g[cur]) {
			if (dst == par) continue;
			dfs2(dst, cur);
		}
		up[cur] = idx_;
	}

public:
	DSUonTree(G &_g, int _root = 0)
			: g(_g),
				N(_g.size()),
				sub_sz(_g.size()),
				euler(_g.size()),
				down(_g.size()),
				up(_g.size()),
				idx_(0),
				root(_root) {
		dfs1(root);
		dfs2(root);
	}

	int idx(int u) const { return down[u]; }

	template <typename UPDATE, typename QUERY, typename CLEAR, typename RESET>
	void run(UPDATE &update, QUERY &query, CLEAR &clear, RESET &reset) {
		auto dsu = [&](auto rc, int cur, int par = -1, bool keep = false) -> void {
			for (int i = 1; i < (int)g[cur].size(); i++)
				if (g[cur][i] != par) rc(rc, g[cur][i], cur, false);
			if (sub_sz[cur] != 1) rc(rc, g[cur][0], cur, true);
			if (sub_sz[cur] != 1)
				for (int i = up[g[cur][0]]; i < up[cur]; i++) update(euler[i]);
			update(cur);
			query(cur);
			if (!keep) {
				for (int i = down[cur]; i < up[cur]; i++) clear(euler[i]);
				reset();
			}
			return;
		};
		dsu(dsu, root);
	}
};

/*-----8<-----library-----8<-----*/

void solve() {
	/*
	//テンプレ
	// 頂点vが追加された時の処理を書く reflect data of node i
	auto update = [&](int v) {

	};
	// 頂点iの部分木クエリに答える answer queries of subtree i
	auto query = [&](int v) {

	};
	// below two function are called if all data must be deleted
	// 頂点vが削除された時の処理を書く delete data of node i (if necesarry)
	auto clear = [&](int v) {

	};
	// 頂点全消去の処理 delete data related to all (if necesarry)
	auto reset = [&]() {

	};
	DSUonTree<decltype(g)> dsu(g, 0);
	dsu.run(update, query, clear, reset);
	*/

	int N, K;
	cin >> N >> K;

	vector<int> U(N-1), V(N-1), C(N), D(N);
	rep(i, N-1) cin >> U[i] >> V[i], U[i]--, V[i]--;
	rep(i, N) cin >> C[i] >> D[i], C[i]--, D[i]--;

	vector<vector<int>> g(N);
	rep(i, N-1) {
		g[U[i]].emplace_back(V[i]);
		g[V[i]].emplace_back(U[i]);
	}

	int sum = 0;
	fmap<int, int> val;
	UnionFindDynamic uf;
	vector<int> ans(N);

	// 頂点vが追加された時の処理を書く reflect data of node i
	auto update = [&](int v) {
		debugr(v);
		debug(uf);
		debug(val);
		debug(sum);
		debug(C[v], D[v]);
		if (!uf.is_same(C[v], D[v])) {
			int rc = uf.root(C[v]);
			int rd = uf.root(D[v]);
			if (uf.size(rc) < uf.size(rd)) swap(rc, rd);
			val[rc] += val[rd];
			uf.unite(C[v], D[v]);
		};
		int r = uf.root(C[v]);
		if (uf.size(r) > val[r]) {
			sum++;
			val[r]++;
		}
	};
	// 頂点iの部分木クエリに答える answer queries of subtree i
	auto query = [&](int v) {
		ans[v] = sum;
	};
	// below two function are called if all data must be deleted
	// 頂点vが削除された時の処理を書く delete data of node i (if necesarry)
	auto clear = [&](int v) {
	};
	// 頂点全消去の処理 delete data related to all (if necesarry)
	auto reset = [&]() {
		sum = 0;
		val.clear();
		uf.clear();
	};
	DSUonTree<decltype(g)> dsu(g, 0);
	dsu.run(update, query, clear, reset);

	rep(i, N) p(ans[i]);
}

//https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2995
signed main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
	std::cout.setf(std::ios::fixed), std::cout.precision(20);
#ifdef LOCAL_DEV
	/*
	std::ifstream in("in.txt");
	std::cin.rdbuf(in.rdbuf());
	//*/
#else
	std::cin.tie(nullptr);
	std::ios::sync_with_stdio(false);
#endif
	//if (argc > 0) for (int i = 0; i < argc; i++) ARGV.emplace_back(argv[i]); // ["./a.out", ...]
	/*
	int Q; cin >> Q; for (int i = 0; i < Q; i++) solve();
	/*/
	solve();
	//*/
	return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 32184
final_rank: 6

code_snippet: // AOJ #2995 Colorful Tree
// 2025.2.21

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

const int NMAX = 100005;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(int n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

int N, K;
vector<int> adj[NMAX];
int cval[NMAX], dval[NMAX];

struct Data {
    unordered_set<int> forced;
    vector<pair<int,int>> freeVertices;
    vector<int> assigned;
    unordered_map<int,int> matchR;
};

vector<int> vis;
int curStamp = 0;

bool tryAssign(Data &D, int freeIdx) {
    int a = D.freeVertices[freeIdx].first;
    int b = D.freeVertices[freeIdx].second;
    for (int candidate : {a, b}) {
        if(D.forced.count(candidate)) continue;
        if(vis[candidate] == curStamp) continue;
        vis[candidate] = curStamp;
        if(D.matchR.find(candidate) == D.matchR.end()){
            D.matchR[candidate] = freeIdx;
            D.assigned[freeIdx] = candidate;
            return true;
        }
        int other = D.matchR[candidate];
        if(tryAssign(D, other)){
            D.matchR[candidate] = freeIdx;
            D.assigned[freeIdx] = candidate;
            return true;
        }
    }
    return false;
}

void addFreeVertex(Data &D, pair<int,int> freePair) {
    int idx = D.freeVertices.size();
    D.freeVertices.push_back(freePair);
    D.assigned.push_back(0);
    curStamp++;
    tryAssign(D, idx);
}

void updateForForced(Data &D, int forcedColor) {
    if(D.forced.count(forcedColor)) return;
    D.forced.insert(forcedColor);
    if(D.matchR.find(forcedColor) != D.matchR.end()){
        int freeIdx = D.matchR[forcedColor];
        D.matchR.erase(forcedColor);
        D.assigned[freeIdx] = 0;
        curStamp++;
        tryAssign(D, freeIdx);
    }
}

void mergeData(Data &dest, Data &src) {
    for (auto col : src.forced) {
        if(dest.forced.count(col) == 0) updateForForced(dest, col);
    }
    for (auto &pr : src.freeVertices) addFreeVertex(dest, pr);
}

Data dfs(int v, int parent, vector<Data> &dp) {
    Data cur;
    if(cval[v] == dval[v]) cur.forced.insert(cval[v]);
    else addFreeVertex(cur, {cval[v], dval[v]});

    for (int nxt : adj[v]) {
        if(nxt == parent) continue;
        Data child = dfs(nxt, v, dp);
        if(child.freeVertices.size() + child.forced.size() > cur.freeVertices.size() + cur.forced.size()){
            mergeData(child, cur);
            cur = move(child);
        } else mergeData(cur, child);
    }
    int ans_v = cur.forced.size() + cur.matchR.size();
    dp[v].forced = cur.forced;
    dp[v].freeVertices = cur.freeVertices;
    dp[v].assigned = cur.assigned;
    dp[v].matchR = cur.matchR;
    static vector<int> ansArr(NMAX, 0);
    ansArr[v] = ans_v;
    return cur;
}

int main() {
    N = Cin(), K = Cin();
    for (int i = 1; i <= N-1; i++){
        int u = Cin(), v = Cin();
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    for (int i = 1; i <= N; i++) cval[i] = Cin(), dval[i] = Cin();

    vis.assign(K+1, 0);
    vector<Data> dp(N+1);
    vector<int> ansArr(N+1, 0);

    function<Data(int, int)> dfs2 = [&](int v, int parent) -> Data {
        Data cur;
        if(cval[v] == dval[v]) cur.forced.insert(cval[v]);
        else addFreeVertex(cur, {cval[v], dval[v]});

        for (int nxt : adj[v]){
            if(nxt == parent) continue;
            Data child = dfs2(nxt, v);
            if(child.freeVertices.size() + child.forced.size() > cur.freeVertices.size() + cur.forced.size()){
                mergeData(child, cur);
                cur = move(child);
            } else mergeData(cur, child);
        }
        ansArr[v] = cur.forced.size() + cur.matchR.size();
        return cur;
    };

    dfs2(1, 0);
    for (int i = 1; i <= N; i++) Cout(ansArr[i]);
    return 0;
}
accuracy: 1
time_ms: 820
memory_kb: 66292
final_rank: 8

code_snippet: // AOJ #2995 Colorful Tree
// 2025.2.21

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

const int NMAX = 100005;
int N, K;
vector<int> adj[NMAX];
int cval[NMAX], dval[NMAX];

struct Data {
    unordered_set<int> forced;
    vector<pair<int,int>> freeVertices;
    vector<int> assigned;
    unordered_map<int,int> matchR;
};

vector<int> vis;
int curStamp = 0;

bool tryAssign(Data &D, int freeIdx) {
    int a = D.freeVertices[freeIdx].first;
    int b = D.freeVertices[freeIdx].second;
    for (int candidate : {a, b}) {
        if(D.forced.count(candidate)) continue;
        if(vis[candidate] == curStamp) continue;
        vis[candidate] = curStamp;
        if(D.matchR.find(candidate) == D.matchR.end()){
            D.matchR[candidate] = freeIdx;
            D.assigned[freeIdx] = candidate;
            return true;
        }
        int other = D.matchR[candidate];
        if(tryAssign(D, other)){
            D.matchR[candidate] = freeIdx;
            D.assigned[freeIdx] = candidate;
            return true;
        }
    }
    return false;
}

void addFreeVertex(Data &D, pair<int,int> freePair) {
    int idx = D.freeVertices.size();
    D.freeVertices.push_back(freePair);
    D.assigned.push_back(0);
    curStamp++;
    tryAssign(D, idx);
}

void updateForForced(Data &D, int forcedColor) {
    if(D.forced.count(forcedColor)) return;
    D.forced.insert(forcedColor);
    if(D.matchR.find(forcedColor) != D.matchR.end()){
        int freeIdx = D.matchR[forcedColor];
        D.matchR.erase(forcedColor);
        D.assigned[freeIdx] = 0;
        curStamp++;
        tryAssign(D, freeIdx);
    }
}

void mergeData(Data &dest, Data &src) {
    for (auto col : src.forced) {
        if(dest.forced.count(col) == 0) updateForForced(dest, col);
    }
    for (auto &pr : src.freeVertices) addFreeVertex(dest, pr);
}

Data dfs(int v, int parent, vector<Data> &dp) {
    Data cur;
    if(cval[v] == dval[v]) cur.forced.insert(cval[v]);
    else addFreeVertex(cur, {cval[v], dval[v]});

    for (int nxt : adj[v]) {
        if(nxt == parent) continue;
        Data child = dfs(nxt, v, dp);
        if(child.freeVertices.size() + child.forced.size() > cur.freeVertices.size() + cur.forced.size()){
            mergeData(child, cur);
            cur = move(child);
        } else mergeData(cur, child);
    }
    int ans_v = cur.forced.size() + cur.matchR.size();
    dp[v].forced = cur.forced;
    dp[v].freeVertices = cur.freeVertices;
    dp[v].assigned = cur.assigned;
    dp[v].matchR = cur.matchR;
    static vector<int> ansArr(NMAX, 0);
    ansArr[v] = ans_v;
    return cur;
}

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

    cin >> N >> K;
    for (int i = 1; i <= N-1; i++){
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    for (int i = 1; i <= N; i++) cin >> cval[i] >> dval[i];

    vis.assign(K+1, 0);
    vector<Data> dp(N+1);
    vector<int> ansArr(N+1, 0);

    function<Data(int, int)> dfs2 = [&](int v, int parent) -> Data {
        Data cur;
        if(cval[v] == dval[v]) cur.forced.insert(cval[v]);
        else addFreeVertex(cur, {cval[v], dval[v]});

        for (int nxt : adj[v]){
            if(nxt == parent) continue;
            Data child = dfs2(nxt, v);
            if(child.freeVertices.size() + child.forced.size() > cur.freeVertices.size() + cur.forced.size()){
                mergeData(child, cur);
                cur = move(child);
            } else mergeData(cur, child);
        }
        ansArr[v] = cur.forced.size() + cur.matchR.size();
        return cur;
    };

    dfs2(1, 0);
    for (int i = 1; i <= N; i++) cout << ansArr[i] << endl;
    return 0;
}
accuracy: 1
time_ms: 880
memory_kb: 66596
final_rank: 9

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

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); 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 uint = unsigned int;
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));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

struct UnionFind{
    map<int,int> par, ec;
    int val = 0;
    UnionFind(){}
    int root(int x) {
        if (!par.count(x)) {
            par[x] = -1;
            return x;
        }
        else if (par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }
    bool same(int x, int y) {return root(x) == root(y);}
    int size(int x) {return -par[root(x)];}
    int get(int x) {
        x = root(x);
        return min(-par[x], ec[x]);
    }
    bool unite(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) {
            val -= get(x);
            ec[x]++;
            val += get(x);
            return false;
        }
        val -= get(x);
        val -= get(y);
        if (size(x) > size(y)) swap(x,y);
        par[y] += par[x];
        par[x] = y;
        ec[y] += ec[x] + 1;
        val += get(y);
        return true;
    }
};

int main() {
    cin.tie(0);
    ios_base::sync_with_stdio(false);
    int N, K;
    cin >> N >> K;
    vector<vector<int>> G(N);
    rep(i,0,N-1) {
        int A, B;
        cin >> A >> B;
        A--, B--;
        G[A].push_back(B);
        G[B].push_back(A);
    }
    vector<pair<int,int>> P(N);
    rep(i,0,N) cin >> P[i].first >> P[i].second, P[i].first--, P[i].second--;
    vector<vector<pair<int,int>>> ES(N);
    vector<UnionFind> UF(N);
    vector<int> ANS(N);
    auto DFS = [&](auto self, int v, int p) -> void {
        UF[v].unite(P[v].first, P[v].second);
        ES[v].push_back(P[v]);
        for (auto nv : G[v]) {
            if (nv == p) continue;
            self(self, nv, v);
            if (ES[v].size() < ES[nv].size()) {
                swap(ES[v], ES[nv]);
                swap(UF[v], UF[nv]);
            }
            for (auto [a,b] : ES[nv]) {
                ES[v].push_back({a,b});
                UF[v].unite(a,b);
            }
        }
        ANS[v] = UF[v].val;
    };
    DFS(DFS,0,-1);
    rep(i,0,N) cout << ANS[i] << endl;
}
accuracy: 1
time_ms: 1400
memory_kb: 175480
final_rank: 14

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

struct dsu{
    vector<pair<int,int>> edge;
    unordered_map<int,int> V,tree;
    int num;

    void make(int u){
        V[u]=-1;
        tree[u]=1;
        num++;
    }
    int find(int u){
        if(!V.count(u))make(u);
        if(V[u]<0)return u;
        return V[u]=find(V[u]);
    }

    void merge(int u,int v){
        u=find(u);
        v=find(v);
        if(u==v){
            if(tree[u]){
                tree[u]=0;
                num--;
            }
            edge.push_back({u,v});
            return;
        }
        if(V[u]>V[v])swap(u,v);
        num-=tree[u]+tree[v];
        V[u]+=V[v];
        V[v]=u;
        edge.push_back({u,v});
        if(tree[u]&&tree[v]){
            num++;
            tree[u]=1;
        }
        else {
            tree[u]=0;
        }
    }
    void merge(pair<int,int> p){merge(p.first,p.second);}
    int ans(){
        return V.size()-num;
    }
};

int N,K;
vector<dsu> D;
vector<int> AN;
vector<vector<int>> G;

void dfs(int n,int p){
    for(int v:G[n]){
        if(p!=v){
            dfs(v,n);
            if(D[n].edge.size()<D[v].edge.size())swap(D[n],D[v]);
            for(auto e:D[v].edge)D[n].merge(e);
        }
    }
    AN[n]=D[n].ans();
}

int main(){
    int N,K;
    cin>>N>>K;
    D.resize(N);
    G.resize(N);
    for(int i=0;i<N-1;i++){
        int u,v;
        cin>>u>>v;
        u--;v--;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    AN.resize(N);
    for(int i=0;i<N;i++){
        int u,v;
        cin>>u>>v;
        D[i].merge(u,v);
    }
    dfs(0,-1);
    for(int i=0;i<N;i++)cout<<AN[i]<<"\n";
}
accuracy: 1
time_ms: 490
memory_kb: 164040
final_rank: 11

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

struct dsu{
    vector<pair<int,int>> edge;
    unordered_map<int,int> V;
    unordered_map<int,bool> tree;
    vector<int> num;

    void init(){num.assign(2,0);};

    int find(int u){
        if(V[u]<0)return u;
        return V[u]=find(V[u]);
    }

    void make(int u){
        V[u]=-1;
        tree[u]=1;
        num[1]++;
    }

    void merge(int u,int v){
        if(!V.count(u))make(u);
        if(!V.count(v))make(v);
        u=find(u);
        v=find(v);
        if(u==v){
            if(tree[u]){
                tree[u]=0;
                num[0]++;
                num[1]--;
            }
            edge.push_back({u,v});
            return;
        }
        if(V[u]>V[v])swap(u,v);
        int cnt=tree[u]+tree[v];
        num[1]-=cnt;
        num[0]-=(2-cnt);
        V[u]+=V[v];
        V[v]=u;
        edge.push_back({u,v});
        if(tree[u]&&tree[v]){
            num[1]++;
            tree[u]=1;
        }
        else {
            num[0]++;
            tree[u]=0;
        }
    }
    void merge(pair<int,int> p){merge(p.first,p.second);}
    int ans(){
        return V.size()-num[1];
    }
};

int N,K;
vector<dsu> D;
vector<int> AN;
vector<vector<int>> G;
vector<pair<int,int>> col;

void dfs(int n,int p){
    D[n].merge(col[n]);
    for(int v:G[n]){
        if(p!=v){
            dfs(v,n);
            if(D[n].edge.size()<D[v].edge.size())swap(D[n],D[v]);
            for(auto e:D[v].edge)D[n].merge(e);
        }
    }
    AN[n]=D[n].ans();
}

int main(){
    int N,K;
    cin>>N>>K;
    D.resize(N);
    for(int i=0;i<N;i++)D[i].init();
    G.resize(N);
    for(int i=0;i<N-1;i++){
        int u,v;
        cin>>u>>v;
        u--;v--;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    col.resize(N);
    AN.resize(N);
    for(int i=0;i<N;i++)cin>>col[i].first>>col[i].second;

    dfs(0,-1);
    for(int i=0;i<N;i++)cout<<AN[i]<<"\n";
}
accuracy: 1
time_ms: 520
memory_kb: 169560
final_rank: 12

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 rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); 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 uint = unsigned int;
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));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}
#line 2 "library/Utility/fastio.hpp"
#include <unistd.h>
namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf

uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio

using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

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

struct X { // Dynamic UF
    unordered_map<int, int> sz;
    unordered_map<int, int> es;
    int val = 0;
    X() {}
    int root(int v) {
        if (!sz.count(v))
            sz[v] = -1;
        if (sz[v] < 0) {
            return v;
        } else
            return sz[v] = root(sz[v]);
    }
    int get(int v) {
        // min(vs,es)
        int rt = root(v);
        return min(-sz[rt], es[rt]);
    }
    int size(int v) {
        return -sz[root(v)];
    }
    bool unite(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) {
            val -= get(x);
            es[x]++;
            val += get(x);
            return 0;
        }
        val -= get(x) + get(y);
        if (size(x) > size(y))
            swap(x, y);
        sz[y] += sz[x];
        es[y] += es[x] + 1;
        sz[x] = y;
        val += get(y);
        return 1;
    }
};

int main() {
    int n, k;
    read(n, k);
    vector g(n, vector<int>());
    rep(_, 0, n - 1) {
        int x, y;
        read(x, y);
        x--, y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    using P = pair<int, int>;
    vector<P> es(n);
    rep(i, 0, n) {
        read(es[i].first, es[i].second);
        es[i].first--, es[i].second--;
    }

    vector<int> ret(n);
    vector<X> Xs(n);
    vector<vector<P>> buf(n);
    auto dfs = [&](auto &dfs, int v, int p) -> void {
        Xs[v].unite(es[v].first, es[v].second);
        buf[v].push_back(es[v]);
        for (auto &to : g[v])
            if (to != p) {
                dfs(dfs, to, v);
                if (SZ(buf[v]) < SZ(buf[to])) {
                    swap(Xs[v], Xs[to]);
                    swap(buf[v], buf[to]);
                }
                for (auto &[x, y] : buf[to]) {
                    buf[v].emplace_back(x, y);
                    Xs[v].unite(x, y);
                }
            }
        ret[v] = Xs[v].val;
    };
    dfs(dfs, 0, -1);
    rep(i, 0, n) print(ret[i]);
    return 0;
}
accuracy: 1
time_ms: 570
memory_kb: 165016
final_rank: 13

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

#define ll long long
#define elif else if
#define vi vector<int>
#define vll vector<ll>
#define vvi vector<vi>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rep2(i, l, r) for (int i = l; i < (r); i++)

struct UnionFind
{
  vector<pair<int, int>> edge;
  int ans = 0;
  map<int, int> par, V_size, E_size;

  int find(int x)
  {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }

  void add_vertex(int v)
  {
    if (par.find(v) == par.end())
    {
      par[v] = v;
      V_size[v] = 1;
      E_size[v] = 0;
    }
  }

  int calc(int V, int E)
  {
    return min(V, E);
  }

  void add_edge(int v, int u)
  {
    add_vertex(v);
    add_vertex(u);
    edge.push_back({v, u});
    v = find(v);
    u = find(u);
    if (v == u)
    {
      ans -= calc(V_size[v], E_size[v]);
      E_size[v]++;
      ans += calc(V_size[v], E_size[v]);
      return;
    }
    ans -= calc(V_size[v], E_size[v]);
    ans -= calc(V_size[u], E_size[u]);
    V_size[v] += V_size[u];
    E_size[v] += E_size[u];
    E_size[v]++;
    ans += calc(V_size[v], E_size[v]);
    par[u] = v;
    return;
  }
};

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  
  int N, K;
  cin >> N >> K;
  vector<vector<int>> edge(N);
  rep(i, N - 1)
  {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    edge[u].push_back(v);
    edge[v].push_back(u);
  }

  vector<UnionFind> Data(N);
  rep(i, N)
  {
    int c, d;
    cin >> c >> d;
    Data[i].add_edge(c, d);
  }

  vector<int> ans(N, 0);

  auto dfs = [&](auto dfs, int v, int p) -> void
  {
    for (auto u : edge[v])
    {
      if (u != p)
        dfs(dfs, u, v);
    }
    ans[v] = Data[v].ans;
    if (v == 0)
      return;
    if (Data[v].edge.size() > Data[p].edge.size())
      swap(Data[v], Data[p]);
    for (auto [c, d] : Data[v].edge)
      Data[p].add_edge(c, d);
  };

  dfs(dfs, 0, -1);
  rep(i, N) cout << ans[i] << "\n";
}
accuracy: 1
time_ms: 1360
memory_kb: 252184
final_rank: 15

code_snippet: #line 1 "a.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2995"
#include <iostream>
#include <unordered_map>
#include <utility>
#include <vector>

#line 4 "/home/kuhaku/home/github/algo/lib/graph/graph.hpp"

/**
 * @brief 重み付きグラフ
 *
 * @tparam T 辺の重みの型
 */
template <class T>
struct Graph {
  private:
    struct _edge {
        constexpr _edge() : _from(), _to(), _weight() {}
        constexpr _edge(int from, int to, T weight) : _from(from), _to(to), _weight(weight) {}
        constexpr bool operator<(const _edge &rhs) const { return weight() < rhs.weight(); }
        constexpr bool operator>(const _edge &rhs) const { return rhs < *this; }

        constexpr int from() const { return _from; }
        constexpr int to() const { return _to; }
        constexpr T weight() const { return _weight; }

      private:
        int _from, _to;
        T _weight;
    };

  public:
    using edge_type = typename Graph<T>::_edge;

    Graph() : _size(), edges() {}
    Graph(int v) : _size(v), edges(v) {}

    const auto &operator[](int i) const { return edges[i]; }
    auto &operator[](int i) { return edges[i]; }
    const auto begin() const { return edges.begin(); }
    auto begin() { return edges.begin(); }
    const auto end() const { return edges.end(); }
    auto end() { return edges.end(); }
    constexpr int size() const { return _size; }

    void add_edge(const edge_type &e) { edges[e.from()].emplace_back(e); }
    void add_edge(int from, int to, T weight = T(1)) { edges[from].emplace_back(from, to, weight); }
    void add_edges(int from, int to, T weight = T(1)) {
        edges[from].emplace_back(from, to, weight);
        edges[to].emplace_back(to, from, weight);
    }

    void input_edge(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            T weight;
            std::cin >> from >> to >> weight;
            add_edge(from - base, to - base, weight);
        }
    }
    void input_edges(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            T weight;
            std::cin >> from >> to >> weight;
            add_edges(from - base, to - base, weight);
        }
    }

  private:
    int _size;
    std::vector<std::vector<edge_type>> edges;
};

template <>
struct Graph<void> {
  private:
    struct _edge {
        constexpr _edge() : _from(), _to() {}
        constexpr _edge(int from, int to) : _from(from), _to(to) {}

        constexpr int from() const { return _from; }
        constexpr int to() const { return _to; }
        constexpr int weight() const { return 1; }
        constexpr bool operator<(const _edge &rhs) const { return weight() < rhs.weight(); }
        constexpr bool operator>(const _edge &rhs) const { return rhs < *this; }

      private:
        int _from, _to;
    };

  public:
    using edge_type = typename Graph<void>::_edge;

    Graph() : _size(), edges() {}
    Graph(int v) : _size(v), edges(v) {}

    const auto &operator[](int i) const { return edges[i]; }
    auto &operator[](int i) { return edges[i]; }
    const auto begin() const { return edges.begin(); }
    auto begin() { return edges.begin(); }
    const auto end() const { return edges.end(); }
    auto end() { return edges.end(); }
    constexpr int size() const { return _size; }

    void add_edge(const edge_type &e) { edges[e.from()].emplace_back(e); }
    void add_edge(int from, int to) { edges[from].emplace_back(from, to); }
    void add_edges(int from, int to) {
        edges[from].emplace_back(from, to);
        edges[to].emplace_back(to, from);
    }

    void input_edge(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            std::cin >> from >> to;
            add_edge(from - base, to - base);
        }
    }
    void input_edges(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            std::cin >> from >> to;
            add_edges(from - base, to - base);
        }
    }

  private:
    int _size;
    std::vector<std::vector<edge_type>> edges;
};
#line 1 "/home/kuhaku/home/github/algo/lib/tree/dsu_on_tree.hpp"
#include <cassert>
#line 2 "/home/kuhaku/home/github/algo/lib/template/template.hpp"
#pragma GCC target("sse4.2,avx2,bmi2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
template <class T, class U>
constexpr bool chmax(T &a, const U &b) {
    return a < (T)b ? a = (T)b, true : false;
}
template <class T, class U>
constexpr bool chmin(T &a, const U &b) {
    return (T)b < a ? a = (T)b, true : false;
}
constexpr std::int64_t INF = 1000000000000000003;
constexpr int Inf = 1000000003;
constexpr double EPS = 1e-7;
constexpr double PI = M_PI;
#line 5 "/home/kuhaku/home/github/algo/lib/tree/dsu_on_tree.hpp"

struct dsu_on_tree {
    dsu_on_tree(const Graph<void> &_g, const std::vector<int> &query, int r = 0)
        : g(_g), size(_g.size()), root(r), par(size, -1), sub(), euler(size), left(size),
          right(size), heavy_path(size, -1), query_order(query.size()), query_size(size) {
        if (size == 0) return;
        for (int x : query) ++query_size[x];
        sub = query_size;
        dfs_sz(root);
        if (size > 1) {
            int pos = 0, len = 0;
            dfs_hld(root, pos, len);
        }
        std::vector<int> cnt = left;
        for (int i = 0; i < (int)query.size(); ++i) query_order[cnt[query[i]]++] = i;
    }

    template <class F, class G, class H>
    void solve(F &rem, G &clear, H &query) {
        auto dsu = [&](auto self, int v) -> void {
            int hp = heavy_path[v];
            if (hp == -1) {
                for (int i = left[v]; i < right[v]; ++i) query(query_order[i]);
                rem(v);
                return;
            }
            for (auto &e : g[v]) {
                if (e.to() == par[v] || e.to() == heavy_path[v]) continue;
                self(self, e.to());
                clear();
            }
            self(self, hp);
            for (int i = left[v]; i < left[hp]; ++i) query(query_order[i]);
            for (int i = right[hp]; i < right[v]; ++i) query(query_order[i]);
            rem(v);
        };
        dsu(dsu, 0);
    }

  private:
    const Graph<void> &g;
    int size, root;
    std::vector<int> par, sub, euler, left, right, heavy_path, query_order, query_size;

    void dfs_sz(int v) {
        int max_sub = 0;
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v]) continue;
            par[u] = v;
            dfs_sz(u);
            sub[v] += sub[u];
            if (chmax(max_sub, sub[u])) heavy_path[v] = u;
        }
    }

    void dfs_hld(int v, int &pos, int &len) {
        euler[pos++] = v;
        left[v] = len;
        right[v] = len + sub[v];
        len += query_size[v];
        int hp = heavy_path[v];
        if (hp == -1) {
            right[v] = len;
            return;
        }
        dfs_hld(hp, pos, len);
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v] || u == hp) continue;
            dfs_hld(u, pos, len);
        }
    }
};
#line 3 "/home/kuhaku/home/github/algo/lib/tree/union_find.hpp"

/**
 * @brief 素集合データ構造
 * @details Implement (union by size) + (path compression)
 * @see https://github.com/atcoder/ac-library/blob/master/atcoder/dsu.hpp
 */
struct union_find {
    union_find() = default;
    explicit union_find(int _n) : _rank(_n), data(_n, -1) {}

    const int &operator[](std::size_t x) const { return data[x]; }
    int &operator[](std::size_t x) { return data[x]; }

    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
    int get_root(int x) { return root(x); }

    bool is_root(int x) const { return data[x] < 0; }

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

    int rank() { return _rank; }

    int size(int x) { return -(data[root(x)]); }
    int get_size(int x) { return size(x); }

    std::vector<int> leaders() {
        std::vector<int> res;
        for (int i = 0; i < (int)data.size(); ++i) {
            if (is_root(i)) res.emplace_back(i);
        }
        return res;
    }

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

    template <class F>
    bool unite(int x, int y, F f) {
        x = root(x), y = root(y);
        if (x != y) {
            if (data[x] > data[y]) std::swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        f(x, y);
        return x != y;
    }

  private:
    int _rank;
    std::vector<int> data;
};
#line 10 "a.cpp"

int main(void) {
    int n, k;
    std::cin >> n >> k;
    Graph<void> g(n);
    g.input_edges(n - 1);
    std::vector<int> ord(n);
    std::iota(ord.begin(), ord.end(), 0);
    dsu_on_tree dsu(g, ord);
    std::vector<std::pair<int, int>> a(n);
    for (auto &[x, y] : a) std::cin >> x >> y, --x, --y;
    std::vector<int> ans(n);
    int sum = 0;
    union_find uf(k);
    std::vector<bool> flag(k);
    std::vector<int> history;
    auto rem = [&](int x) {
        ans[x] = sum;
    };
    auto clear = [&]() {
        sum = 0;
        for (int x : history) {
            uf[x] = -1;
            flag[x] = false;
        }
        history.clear();
    };
    auto f = [&](int x, int y) {
        if (x == y) {
            if (!flag[x]) {
                ++sum;
                flag[x] = true;
            }
        } else {
            if (!flag[x] || !flag[y])
                ++sum;
            flag[x] = flag[x] | flag[y];
        }
    };
    auto query = [&](int v) {
        auto [s, t] = a[v];
        uf.unite(s, t, f);
        history.emplace_back(s);
        history.emplace_back(t);
    };
    dsu.solve(rem, clear, query);
    for (int i = 0; i < n; ++i) std::cout << ans[i] << '\n';

    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 40476
final_rank: 5

code_snippet: #line 1 "a.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2995"
#line 2 "/home/kuhaku/home/github/algo/lib/graph/graph.hpp"
#include <iostream>
#include <vector>

/**
 * @brief 重み付きグラフ
 *
 * @tparam T 辺の重みの型
 */
template <class T>
struct Graph {
  private:
    struct _edge {
        constexpr _edge() : _from(), _to(), _weight() {}
        constexpr _edge(int from, int to, T weight) : _from(from), _to(to), _weight(weight) {}
        constexpr bool operator<(const _edge &rhs) const { return weight() < rhs.weight(); }
        constexpr bool operator>(const _edge &rhs) const { return rhs < *this; }

        constexpr int from() const { return _from; }
        constexpr int to() const { return _to; }
        constexpr T weight() const { return _weight; }

      private:
        int _from, _to;
        T _weight;
    };

  public:
    using edge_type = typename Graph<T>::_edge;

    Graph() : _size(), edges() {}
    Graph(int v) : _size(v), edges(v) {}

    const auto &operator[](int i) const { return edges[i]; }
    auto &operator[](int i) { return edges[i]; }
    const auto begin() const { return edges.begin(); }
    auto begin() { return edges.begin(); }
    const auto end() const { return edges.end(); }
    auto end() { return edges.end(); }
    constexpr int size() const { return _size; }

    void add_edge(const edge_type &e) { edges[e.from()].emplace_back(e); }
    void add_edge(int from, int to, T weight = T(1)) { edges[from].emplace_back(from, to, weight); }
    void add_edges(int from, int to, T weight = T(1)) {
        edges[from].emplace_back(from, to, weight);
        edges[to].emplace_back(to, from, weight);
    }

    void input_edge(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            T weight;
            std::cin >> from >> to >> weight;
            add_edge(from - base, to - base, weight);
        }
    }
    void input_edges(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            T weight;
            std::cin >> from >> to >> weight;
            add_edges(from - base, to - base, weight);
        }
    }

  private:
    int _size;
    std::vector<std::vector<edge_type>> edges;
};

template <>
struct Graph<void> {
  private:
    struct _edge {
        constexpr _edge() : _from(), _to() {}
        constexpr _edge(int from, int to) : _from(from), _to(to) {}

        constexpr int from() const { return _from; }
        constexpr int to() const { return _to; }
        constexpr int weight() const { return 1; }
        constexpr bool operator<(const _edge &rhs) const { return weight() < rhs.weight(); }
        constexpr bool operator>(const _edge &rhs) const { return rhs < *this; }

      private:
        int _from, _to;
    };

  public:
    using edge_type = typename Graph<void>::_edge;

    Graph() : _size(), edges() {}
    Graph(int v) : _size(v), edges(v) {}

    const auto &operator[](int i) const { return edges[i]; }
    auto &operator[](int i) { return edges[i]; }
    const auto begin() const { return edges.begin(); }
    auto begin() { return edges.begin(); }
    const auto end() const { return edges.end(); }
    auto end() { return edges.end(); }
    constexpr int size() const { return _size; }

    void add_edge(const edge_type &e) { edges[e.from()].emplace_back(e); }
    void add_edge(int from, int to) { edges[from].emplace_back(from, to); }
    void add_edges(int from, int to) {
        edges[from].emplace_back(from, to);
        edges[to].emplace_back(to, from);
    }

    void input_edge(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            std::cin >> from >> to;
            add_edge(from - base, to - base);
        }
    }
    void input_edges(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            std::cin >> from >> to;
            add_edges(from - base, to - base);
        }
    }

  private:
    int _size;
    std::vector<std::vector<edge_type>> edges;
};
#line 2 "/home/kuhaku/home/github/algo/lib/template/template.hpp"
#pragma GCC target("sse4.2,avx2,bmi2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
template <class T, class U>
constexpr bool chmax(T &a, const U &b) {
    return a < (T)b ? a = (T)b, true : false;
}
template <class T, class U>
constexpr bool chmin(T &a, const U &b) {
    return (T)b < a ? a = (T)b, true : false;
}
constexpr std::int64_t INF = 1000000000000000003;
constexpr int Inf = 1000000003;
constexpr double EPS = 1e-7;
constexpr double PI = M_PI;
#line 3 "/home/kuhaku/home/github/algo/lib/template/macro.hpp"
#define FOR(i, m, n) for (int i = (m); i < int(n); ++i)
#define FORR(i, m, n) for (int i = (m)-1; i >= int(n); --i)
#define FORL(i, m, n) for (int64_t i = (m); i < int64_t(n); ++i)
#define rep(i, n) FOR (i, 0, n)
#define repn(i, n) FOR (i, 1, n + 1)
#define repr(i, n) FORR (i, n, 0)
#define repnr(i, n) FORR (i, n + 1, 1)
#define all(s) (s).begin(), (s).end()
#line 3 "/home/kuhaku/home/github/algo/lib/template/sonic.hpp"
struct Sonic {
    Sonic() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout << std::fixed << std::setprecision(20);
    }

    constexpr void operator()() const {}
} sonic;
#line 5 "/home/kuhaku/home/github/algo/lib/template/atcoder.hpp"
using namespace std;
using ll = std::int64_t;
using ld = long double;
template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
    return is >> p.first >> p.second;
}
template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
    for (T &i : v) is >> i;
    return is;
}
template <class T, class U>
std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &p) {
    return os << '(' << p.first << ',' << p.second << ')';
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
    for (auto it = v.begin(); it != v.end(); ++it) {
        os << (it == v.begin() ? "" : " ") << *it;
    }
    return os;
}
template <class Head, class... Tail>
void co(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cout << head << '\n';
    else std::cout << head << ' ', co(std::forward<Tail>(tail)...);
}
template <class Head, class... Tail>
void ce(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cerr << head << '\n';
    else std::cerr << head << ' ', ce(std::forward<Tail>(tail)...);
}
template <typename T, typename... Args>
auto make_vector(T x, int arg, Args... args) {
    if constexpr (sizeof...(args) == 0) return std::vector<T>(arg, x);
    else return std::vector(arg, make_vector<T>(x, args...));
}
void Yes(bool is_correct = true) {
    std::cout << (is_correct ? "Yes" : "No") << '\n';
}
void No(bool is_not_correct = true) {
    Yes(!is_not_correct);
}
void YES(bool is_correct = true) {
    std::cout << (is_correct ? "YES" : "NO") << '\n';
}
void NO(bool is_not_correct = true) {
    YES(!is_not_correct);
}
void Takahashi(bool is_correct = true) {
    std::cout << (is_correct ? "Takahashi" : "Aoki") << '\n';
}
void Aoki(bool is_not_correct = true) {
    Takahashi(!is_not_correct);
}
#line 3 "/home/kuhaku/home/github/algo/lib/tree/dsu_on_tree.hpp"

struct dsu_on_tree {
    template <class T>
    dsu_on_tree(const Graph<T> &g, int r = 0)
        : size(g.size()), root(r), par(size, -1), sub(size, 1), euler(size), left(size),
          right(size) {
        if (size == 0) return;
        std::vector<int> heavy_path(size, -1);
        dfs_sz(g, root, heavy_path);
        euler[0] = root;
        if (size > 1) {
            int pos = 1;
            dfs_hld(g, root, pos, heavy_path);
        }
    }

    template <class F, class G, class H, class I>
    void solve(F &rem, G &clear, H &query_vertex, I &query_edge) {
        auto dsu = [&](auto self, int v) -> void {
            if (left[v] == right[v]) {
                query_vertex(v);
                rem(v);
                return;
            }
            for (int i = left[v] + 1; i < size && par[euler[i]] == v; ++i) {
                self(self, euler[i]);
                clear();
            }
            self(self, euler[left[v]]);
            for (int i = left[v] + 1; i < left[euler[left[v]]]; ++i) {
                query_vertex(euler[i]);
                query_edge(par[euler[i]], euler[i]);
            }
            for (int i = right[euler[left[v]]]; i < right[v]; ++i) {
                query_vertex(euler[i]);
                query_edge(par[euler[i]], euler[i]);
            }
            query_vertex(v);
            rem(v);
        };
        dsu(dsu, 0);
    }

  private:
    int size, root;
    std::vector<int> par, sub, euler, left, right, heavy_path;

    template <class T>
    void dfs_sz(const Graph<T> &g, int v, std::vector<int> &heavy_path) {
        int max_sub = 0;
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v]) continue;
            par[u] = v;
            dfs_sz(g, u, heavy_path);
            sub[v] += sub[u];
            if (chmax(max_sub, sub[u])) heavy_path[v] = u;
        }
    }

    template <class T>
    void dfs_hld(const Graph<T> &g, int v, int &pos, std::vector<int> &heavy_path) {
        left[v] = pos;
        int hp = heavy_path[v];
        if (hp != -1) euler[pos++] = hp;
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v] || u == hp) continue;
            euler[pos++] = u;
        }
        if (hp != -1) dfs_hld(g, hp, pos, heavy_path);
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v] || u == hp) continue;
            dfs_hld(g, u, pos, heavy_path);
        }
        right[v] = pos;
    }
};
#line 3 "/home/kuhaku/home/github/algo/lib/tree/union_find.hpp"

/**
 * @brief 素集合データ構造
 * @details Implement (union by size) + (path compression)
 * @see https://github.com/atcoder/ac-library/blob/master/atcoder/dsu.hpp
 */
struct union_find {
    union_find() = default;
    explicit union_find(int _n) : _rank(_n), data(_n, -1) {}

    const int &operator[](std::size_t x) const { return data[x]; }
    int &operator[](std::size_t x) { return data[x]; }

    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
    int get_root(int x) { return root(x); }

    bool is_root(int x) const { return data[x] < 0; }

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

    int rank() { return _rank; }

    int size(int x) { return -(data[root(x)]); }
    int get_size(int x) { return size(x); }

    std::vector<int> leaders() {
        std::vector<int> res;
        for (int i = 0; i < (int)data.size(); ++i) {
            if (is_root(i)) res.emplace_back(i);
        }
        return res;
    }

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

    template <class F>
    bool unite(int x, int y, F f) {
        x = root(x), y = root(y);
        if (x != y) {
            if (data[x] > data[y]) std::swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        f(x, y);
        return x != y;
    }

  private:
    int _rank;
    std::vector<int> data;
};
#line 6 "a.cpp"

int main(void) {
    int n, k;
    cin >> n >> k;
    Graph<void> g(n);
    g.input_edges(n - 1);
    dsu_on_tree dsu(g);
    vector<pair<int, int>> a(n);
    for (auto &[x, y] : a) {
        std::cin >> x >> y;
        --x, --y;
    }
    vector<int> ans(n);
    int sum = 0;
    union_find uf(k);
    vector<bool> flag(k);
    vector<int> history;
    auto rem = [&](int x) {
        ans[x] = sum;
    };
    auto clear = [&]() {
        sum = 0;
        for (int x : history) {
            uf[x] = -1;
            flag[x] = false;
        }
        history.clear();
    };
    auto f = [&](int x, int y) {
        if (x == y) {
            if (!flag[x]) {
                ++sum;
                flag[x] = true;
            }
        } else {
            if (!flag[x] || !flag[y])
                ++sum;
            flag[x] = flag[x] | flag[y];
        }
    };
    auto query_vertex = [&](int v) {
        auto [s, t] = a[v];
        uf.unite(s, t, f);
        history.emplace_back(s);
        history.emplace_back(t);
    };
    auto query_edge = [&](int u, int v) {};
    dsu.solve(rem, clear, query_vertex, query_edge);
    rep (i, n) co(ans[i]);

    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 37444
final_rank: 3

code_snippet: #line 1 "a.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2995"
#include <iostream>
#include <unordered_map>
#include <utility>
#include <vector>

#line 4 "/home/kuhaku/home/github/algo/lib/graph/graph.hpp"

/**
 * @brief 重み付きグラフ
 *
 * @tparam T 辺の重みの型
 */
template <class T>
struct Graph {
  private:
    struct _edge {
        constexpr _edge() : _from(), _to(), _weight() {}
        constexpr _edge(int from, int to, T weight) : _from(from), _to(to), _weight(weight) {}
        constexpr bool operator<(const _edge &rhs) const { return weight() < rhs.weight(); }
        constexpr bool operator>(const _edge &rhs) const { return rhs < *this; }

        constexpr int from() const { return _from; }
        constexpr int to() const { return _to; }
        constexpr T weight() const { return _weight; }

      private:
        int _from, _to;
        T _weight;
    };

  public:
    using edge_type = typename Graph<T>::_edge;

    Graph() : _size(), edges() {}
    Graph(int v) : _size(v), edges(v) {}

    const auto &operator[](int i) const { return edges[i]; }
    auto &operator[](int i) { return edges[i]; }
    const auto begin() const { return edges.begin(); }
    auto begin() { return edges.begin(); }
    const auto end() const { return edges.end(); }
    auto end() { return edges.end(); }
    constexpr int size() const { return _size; }

    void add_edge(const edge_type &e) { edges[e.from()].emplace_back(e); }
    void add_edge(int from, int to, T weight = T(1)) { edges[from].emplace_back(from, to, weight); }
    void add_edges(int from, int to, T weight = T(1)) {
        edges[from].emplace_back(from, to, weight);
        edges[to].emplace_back(to, from, weight);
    }

    void input_edge(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            T weight;
            std::cin >> from >> to >> weight;
            add_edge(from - base, to - base, weight);
        }
    }
    void input_edges(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            T weight;
            std::cin >> from >> to >> weight;
            add_edges(from - base, to - base, weight);
        }
    }

  private:
    int _size;
    std::vector<std::vector<edge_type>> edges;
};

template <>
struct Graph<void> {
  private:
    struct _edge {
        constexpr _edge() : _from(), _to() {}
        constexpr _edge(int from, int to) : _from(from), _to(to) {}

        constexpr int from() const { return _from; }
        constexpr int to() const { return _to; }
        constexpr int weight() const { return 1; }
        constexpr bool operator<(const _edge &rhs) const { return weight() < rhs.weight(); }
        constexpr bool operator>(const _edge &rhs) const { return rhs < *this; }

      private:
        int _from, _to;
    };

  public:
    using edge_type = typename Graph<void>::_edge;

    Graph() : _size(), edges() {}
    Graph(int v) : _size(v), edges(v) {}

    const auto &operator[](int i) const { return edges[i]; }
    auto &operator[](int i) { return edges[i]; }
    const auto begin() const { return edges.begin(); }
    auto begin() { return edges.begin(); }
    const auto end() const { return edges.end(); }
    auto end() { return edges.end(); }
    constexpr int size() const { return _size; }

    void add_edge(const edge_type &e) { edges[e.from()].emplace_back(e); }
    void add_edge(int from, int to) { edges[from].emplace_back(from, to); }
    void add_edges(int from, int to) {
        edges[from].emplace_back(from, to);
        edges[to].emplace_back(to, from);
    }

    void input_edge(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            std::cin >> from >> to;
            add_edge(from - base, to - base);
        }
    }
    void input_edges(int m, int base = 1) {
        for (int i = 0; i < m; ++i) {
            int from, to;
            std::cin >> from >> to;
            add_edges(from - base, to - base);
        }
    }

  private:
    int _size;
    std::vector<std::vector<edge_type>> edges;
};
#line 1 "/home/kuhaku/home/github/algo/lib/tree/dsu_on_tree.hpp"
#include <cassert>
#line 2 "/home/kuhaku/home/github/algo/lib/template/template.hpp"
#pragma GCC target("sse4.2,avx2,bmi2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
template <class T, class U>
constexpr bool chmax(T &a, const U &b) {
    return a < (T)b ? a = (T)b, true : false;
}
template <class T, class U>
constexpr bool chmin(T &a, const U &b) {
    return (T)b < a ? a = (T)b, true : false;
}
constexpr std::int64_t INF = 1000000000000000003;
constexpr int Inf = 1000000003;
constexpr double EPS = 1e-7;
constexpr double PI = M_PI;
#line 5 "/home/kuhaku/home/github/algo/lib/tree/dsu_on_tree.hpp"

struct dsu_on_tree {
    template <class T>
    dsu_on_tree(const Graph<T> &g, int r = 0)
        : size(g.size()), root(r), par(size, -1), sub(size, 1), euler(size), left(size),
          right(size) {
        if (size == 0) return;
        std::vector<int> heavy_path(size, -1);
        dfs_sz(g, root, heavy_path);
        euler[0] = root;
        if (size > 1) {
            int pos = 1;
            dfs_hld(g, root, pos, heavy_path);
        }
    }

    template <class F, class G, class H, class I>
    void solve(F &rem, G &clear, H &query_vertex, I &query_edge) {
        auto dsu = [&](auto self, int v) -> void {
            if (left[v] == right[v]) {
                query_vertex(v);
                rem(v);
                return;
            }
            for (int i = left[v] + 1; i < size && par[euler[i]] == v; ++i) {
                self(self, euler[i]);
                clear();
            }
            self(self, euler[left[v]]);
            for (int i = left[v] + 1; i < left[euler[left[v]]]; ++i) {
                query_vertex(euler[i]);
                query_edge(par[euler[i]], euler[i]);
            }
            for (int i = right[euler[left[v]]]; i < right[v]; ++i) {
                query_vertex(euler[i]);
                query_edge(par[euler[i]], euler[i]);
            }
            query_vertex(v);
            rem(v);
        };
        dsu(dsu, 0);
    }

  private:
    int size, root;
    std::vector<int> par, sub, euler, left, right;

    template <class T>
    void dfs_sz(const Graph<T> &g, int v, std::vector<int> &heavy_path) {
        int max_sub = 0;
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v]) continue;
            par[u] = v;
            dfs_sz(g, u, heavy_path);
            sub[v] += sub[u];
            if (chmax(max_sub, sub[u])) heavy_path[v] = u;
        }
    }

    template <class T>
    void dfs_hld(const Graph<T> &g, int v, int &pos, std::vector<int> &heavy_path) {
        left[v] = pos;
        int hp = heavy_path[v];
        if (hp != -1) euler[pos++] = hp;
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v] || u == hp) continue;
            euler[pos++] = u;
        }
        if (hp != -1) dfs_hld(g, hp, pos, heavy_path);
        for (auto &e : g[v]) {
            int u = e.to();
            if (u == par[v] || u == hp) continue;
            dfs_hld(g, u, pos, heavy_path);
        }
        right[v] = pos;
    }
};
#line 3 "/home/kuhaku/home/github/algo/lib/tree/union_find.hpp"

/**
 * @brief 素集合データ構造
 * @details Implement (union by size) + (path compression)
 * @see https://github.com/atcoder/ac-library/blob/master/atcoder/dsu.hpp
 */
struct union_find {
    union_find() = default;
    explicit union_find(int _n) : _rank(_n), data(_n, -1) {}

    const int &operator[](std::size_t x) const { return data[x]; }
    int &operator[](std::size_t x) { return data[x]; }

    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
    int get_root(int x) { return root(x); }

    bool is_root(int x) const { return data[x] < 0; }

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

    int rank() { return _rank; }

    int size(int x) { return -(data[root(x)]); }
    int get_size(int x) { return size(x); }

    std::vector<int> leaders() {
        std::vector<int> res;
        for (int i = 0; i < (int)data.size(); ++i) {
            if (is_root(i)) res.emplace_back(i);
        }
        return res;
    }

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

    template <class F>
    bool unite(int x, int y, F f) {
        x = root(x), y = root(y);
        if (x != y) {
            if (data[x] > data[y]) std::swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        f(x, y);
        return x != y;
    }

  private:
    int _rank;
    std::vector<int> data;
};
#line 10 "a.cpp"

int main(void) {
    int n, k;
    std::cin >> n >> k;
    Graph<void> g(n);
    g.input_edges(n - 1);
    dsu_on_tree dsu(g);
    std::vector<std::pair<int, int>> a(n);
    for (auto &[x, y] : a) std::cin >> x >> y, --x, --y;
    std::vector<int> ans(n);
    int sum = 0;
    union_find uf(k);
    std::vector<bool> flag(k);
    std::vector<int> history;
    auto rem = [&](int x) {
        ans[x] = sum;
    };
    auto clear = [&]() {
        sum = 0;
        for (int x : history) {
            uf[x] = -1;
            flag[x] = false;
        }
        history.clear();
    };
    auto f = [&](int x, int y) {
        if (x == y) {
            if (!flag[x]) {
                ++sum;
                flag[x] = true;
            }
        } else {
            if (!flag[x] || !flag[y])
                ++sum;
            flag[x] = flag[x] | flag[y];
        }
    };
    auto query_vertex = [&](int v) {
        auto [s, t] = a[v];
        uf.unite(s, t, f);
        history.emplace_back(s);
        history.emplace_back(t);
    };
    auto query_edge = [&](int u, int v) {};
    dsu.solve(rem, clear, query_vertex, query_edge);
    for (int i = 0; i < n; ++i) std::cout << ans[i] << '\n';

    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 37416
final_rank: 4