这道题就是标记每个点对其所在子树的颜色增加的贡献值,如果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" ); } }