dsu on tee相关题目练习(DFS)
1.U41492 树上数颜色
dsu on tree 裸题,具体看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
vector<int>v[N];
int col[N],hev[N],sz[N],cnt[N],mx,son,n;
ll sum,ans[N];
void dfs1(int u,int fa){
sz[u]=1;
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i];
if(to!=fa)
{
dfs1(to,u);
sz[u]+=sz[to];
if(sz[to]>sz[hev[u]]) hev[u]=to;//更新轻重链部分
}
}
}
void add(int u,int fa,int val){
//printf("u=%d,fa=%d,val=%d\n",u,fa,val);
cnt[col[u]]+=val;
if(val==1&&cnt[col[u]]==1) sum++; ///根据题目要求修改。
else if(val==-1&&cnt[col[u]]==0) sum--;
for(int i=0;i<v[u].size();i++){
int to=v[u][i];
if(to!=fa&&to!=son) //统计所有轻儿子贡献。
add(to,u,val);
}
}
void dfs2(int u,int fa,int opt){ //opt表示十分消除贡献 0表示消除,1表示不消除
//printf("u=%d,fa=%d,opt%d\n",u,fa,opt);
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i];
if(to!=fa&&to!=hev[u])
dfs2(to,u,0);//搜索所有轻边,递归完成后消除对该点的影响
}
if(hev[u]) dfs2(hev[u],u,1),son=hev[u];//搜索重边,且不消除影响。
//最后搜索重边不删除影响 叶子结点没有轻儿子,相当于自己就是轻儿子。下面的add(u,fa,1)就是加上自己
add(u,fa,1),son=0;//暴力统计所有轻儿子的贡献
ans[u]=sum;
if(!opt) add(u,fa,-1),sum=mx=0;//如果不是重儿子就消除影响,如果是重儿子(最后搜索)就保存影响。最后直接加上轻儿子的贡献就是总贡献
}
int main(){
cin>>n;
for(int i=1,a,b;i<=n-1;i++)
{
cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
for(int i=1;i<=n;i++) cin>>col[i];
dfs1(1,0);
dfs2(1,0,0);
for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}
2.E. Lomsat gelral
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
vector<int>v[N];
int col[N],hev[N],sz[N],cnt[N],mx,son,n;
ll sum,ans[N];
void dfs1(int u,int fa){
sz[u]=1;
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i];
if(to!=fa)
{
dfs1(to,u);
sz[u]+=sz[to];
if(sz[to]>sz[hev[u]]) hev[u]=to;//更新轻重链部分
}
}
}
void add(int u,int fa,int val){
//printf("u=%d,fa=%d,val=%d\n",u,fa,val);
cnt[col[u]]+=val; ///这一块根据题目具体要求修改
if(cnt[col[u]]>mx) mx=cnt[col[u]],sum=col[u];
else if(cnt[col[u]]==mx) sum+=(ll)col[u];
for(int i=0;i<v[u].size();i++){
int to=v[u][i];
if(to!=fa&&to!=son) //统计所有轻儿子贡献。
add(to,u,val);
}
}
void dfs2(int u,int fa,int opt){ //opt表示十分消除贡献 0表示消除,1表示不消除
printf("u=%d,fa=%d,opt%d\n",u,fa,opt);
for(int i=0;i<v[u].size();i++) ////搜索n个结点复杂度 O(n) 任意点到根的路径最多有logn个轻边 重边不用删除 所以时间复杂度为O(nlogn)
{
int to=v[u][i];
if(to!=fa&&to!=hev[u])
dfs2(to,u,0);//搜索所有轻边,递归完成后消除对该点的影响
}
if(hev[u]) dfs2(hev[u],u,1),son=hev[u];//搜索重边,且不消除影响。
//最后搜索重边不删除影响 叶子结点没有轻儿子,相当于自己就是轻儿子。下面的add(u,fa,1)就是加上自己
add(u,fa,1),son=0;//暴力统计所有轻儿子的贡献
ans[u]=sum;
if(!opt) add(u,fa,-1),sum=mx=0;//如果不是重儿子就消除影响,如果是重儿子(最后搜索)就保存影响。最后直接加上轻儿子的贡献就是总贡献
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>col[i];
for(int i=1,a,b;i<=n-1;i++)
{
cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
dfs1(1,0);
dfs2(1,0,0);
for(int i=1;i<=n;i++) printf(i==n?"%lld\n":"%lld ",ans[i]);
return 0;
}