HDU6035-Colorful Tree-虚树思想
link:https://codeforces.com/gym/102253/problem/C
题意:一棵树,每个点有颜色,求所有路径上出现的颜色个数之和,基本要求线性。
对每种颜色考虑答案,枚举到颜色c的时候想着把所有颜色c的点拿出来,建立虚树,这样总的点数是
对这个虚树考虑,如果颜色c用黑点表示,那么假设删去黑点,树会变成若干连通块,这个颜色的贡献就是
考虑从上往下模拟这个dfs的过程,对当前的结点x,对每个孩子结点
这个子树大小可以通过一些类似树上差分的技巧完成:dfs时记录每种颜色当前还“剩下”几个点,一开始全部设为
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define endl '\n' #define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N=2e5+5; int n,c[N],sz[N],cnt[N]; vector<vector<int>> G; ll ans; ll C2(int n){return (ll)n*(n-1)/2;} void dfs1(int x,int fa){ sz[x]=1; for(auto to:G[x])if(to!=fa){ dfs1(to,x); sz[x]+=sz[to]; } } void dfs2(int x,int fa){ if(x==1)rep(i,1,n)cnt[i]=n; int cur=cnt[c[x]]; for(auto to:G[x])if(to!=fa){ int before=cnt[c[x]]; dfs2(to,x); int after=cnt[c[x]]; int del=sz[to]-(before-after); ans+=C2(del); cnt[c[x]]-=del; } int lst=cnt[c[x]]; cnt[c[x]]-=sz[x]-(cur-lst); if(x==1)rep(i,1,n)ans+=C2(cnt[i]); } int main(){ fastio; int tc=0; while(cin>>n){ tc++; rep(i,1,n)cin>>c[i]; G=vector<vector<int>>(n+1); ans=0; rep(i,1,n-1){ int u,v; cin>>u>>v; G[u].push_back(v); G[v].push_back(u); } dfs1(1,-1); dfs2(1,-1); cout<<"Case #"<<tc<<": "<<n*C2(n)-ans<<endl; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2021-08-19 [笔记]动态规划入门