这道题就是标记每个点对其所在子树的颜色增加的贡献值,如果u和v颜色相同,那么其中一个在此公共祖先l到根的路径贡献要-1,所以在l处先减去1,相当于抛弃这一对点中前一个点对颜色数增加的贡献,再用第二个和后面的取最近公共祖先,依次类推.最终再将将子节点的颜色数加在一起即可(重复已经事先减去),可以看做当下每个节点都能贡献1
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define MAXN 100007
#define MAX 1500007
using namespace std;
int fa[MAXN];
int find ( int x )
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
struct
{
int v,next;
}e[2][MAX];
void scan ( int&x )
{
char c;
x = 0;
c = getchar ( );
while ( c < '0' || c >'9' ) c = getchar ();
while ( c >= '0' && c <= '9' )
{
x = x * 10 + c - 48;
c = getchar( );
}
}
int cc = 0;
int head[2][MAXN];
int num[MAXN];
vector<int> a[MAXN];
vector<int> b[MAX];
void add ( int flag , int u , int v )
{
e[flag][cc].v = v;
e[flag][cc].next = head[flag][u];
head[flag][u] = cc++;
}
void lca ( int u = 1 , int p = -1 )
{
for ( int i = head[0][u] ; i != -1 ; i= e[0][i].next )
{
int v = e[0][i].v;
if ( v == p ) continue;
lca ( v , u );
fa[v] = u;
}
for ( int i = head[1][u] ; i != -1 ; i = e[1][i].next )
{
int v = e[1][i].v;
num[find(v)]--;
}
}
void dfs ( int u = 1 , int p = -1 )
{
int len = a[u].size ( );
for ( int i = 0 ; i < len ; i++ )
b[a[u][i]].push_back ( u );
for ( int i = head[0][u] ; i != -1 ; i = e[0][i].next )
{
int v = e[0][i].v;
if ( v == p ) continue;
dfs ( v , u );
}
}
void calc ( int u = 1 , int p = 0 )
{
for ( int i = head[0][u] ; i != -1 ; i = e[0][i].next )
{
int v = e[0][i].v;
if ( v == p ) continue;
calc ( v , u );
}
num[p] += num[u];
}
int n,m;
int main ( )
{
int u,v;
while ( ~scanf ( "%d%d" , &n , &m ) )
{
cc = 0;
for ( int i = 1 ; i <= n ; i ++ )
fa[i] = i;
memset ( head , -1 , sizeof ( head ) );
memset ( num , 0 , sizeof ( num ) );
for ( int i = 1 ; i < n ; i++ )
{
scan ( u );
scan ( v );
add ( 0 , u , v );
add ( 0 , v , u );
}
cc = 0;
int up = 0;
for ( int i = 0 ; i < m ; i++ )
{
scan ( u );
scan ( v );
a[u].push_back ( v );
up = max ( v , up );
}
dfs ( );
for ( int i = 1 ; i <= up ; i++ )
{
int len = b[i].size();
if ( len == 0 ) continue;
else if ( len == 1 )
num[b[i][0]]++ , b[i].clear();
else
{
int pre = b[i][0];
num[b[i][0]]++;
for ( int j = 1 ; j < len ; j ++ )
{
int v = b[i][j];
add ( 1 , v , pre );
num[v]++;
pre = v;
}
b[i].clear();
}
}
lca ( );
calc ( );
for ( int i = 1 ; i <= n ; i++ ) a[i].clear();
printf ( "%d" , num[1] );
for ( int i = 2 ; i <= n ; i++ )
printf ( " %d" , num[i] );
printf ( "\n" );
}
}