CF600E Lomsat gelral 题解

Statement

CF600E Lomsat gelral - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Solution

第一眼线段树合并,想到有点码量,直接看题解

题解大部分都是 DSU on Tree,突然发现了 CF600E - 辰星凌 - 博客园 (cnblogs.com) 这样一篇神奇思路用的 DFS 序+分治 ,给出了另外一个统计子树信息的思路

有结论

dfn[i]<dfn[i],若存在一个 dfn[j] 满足 dfn[i]dfn[j]dfn[i]+siz[i]1dfn[i]dfn[j]dfn[i]+siz[i]1,那么 一定有 ii 的祖先

我们暴力的想法是对于一个点 i ,暴力统计以下所有 j 满足 dfn[i]dfn[j]dfn[i]+siz[i]1 ,即子树中的点的信息

我们发现这样很浪费,因为很多信息被反复加入又删除

借助上面的结论,我们知道了其实对于满足 dfn[i]dfn[j]dfn[i]+siz[i]1 的点之间有某种关系,比如 i 可以把 i 的信息全部嫖了

所以我们考虑分治 dfs

对于当前分治到的 dfs 序区间 (l,r),我们把 mid 看作上面结论中的 dfn[j] ,从 mid 倒序枚举到 l ,我们可以得到所有 ans[i] 满足 ldfn[i]midmid<dfn[i]+siz[i]1r (具体看代码)

复杂度 O(nlogn)

Orz 辰星凌 - 博客园 (cnblogs.com)

Code

#include<bits/stdc++.h>
#define int long long
#define mid ((l+r)>>1)
using namespace std;
const int N = 1e5+5;

char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read(){
    int s=0,w=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
    return s*w;
}

int c[N],siz[N],dfn[N],rev[N],ans[N],cnt[N],tmp[N];
vector<int>Edge[N];
int n,tim,top,as,mx;

void dfs(int u,int fath){
    siz[u]=1,rev[dfn[u]=++tim]=u;
    for(auto v:Edge[u])if(v^fath)
        dfs(v,u),siz[u]+=siz[v];
}
void clear(){while(top)cnt[tmp[top--]]=0;as=mx=0;}
void insert(int u){
    ++cnt[tmp[++top]=c[u]];
    if(cnt[c[u]]>mx)mx=cnt[c[u]],as=c[u];
    else if(cnt[c[u]]==mx)as+=c[u];
}
void solve(int l,int r){
    if(l==r){
        if(siz[rev[l]]==1)
            ans[rev[l]]=c[rev[l]];
        return ;
    }
    solve(l,mid),solve(mid+1,r),clear();
    for(int i=mid,p=mid,j;j=i+siz[rev[i]]-1,i>=l&&j<=r;--i){
        //注意这里的 j 和上面所述的 j 的意义不大一样
        insert(rev[i]);//时刻注意我们的 i 代表的是一个 dfn 值
        if(j<=mid)continue;
        while(p<j)insert(rev[++p]);//加入子树内的点
        ans[rev[i]]=as;
    }
}

signed main(){
    n=read();
    for(int i=1;i<=n;++i)c[i]=read();
    for(int i=1,u,v;i<n;++i)
        u=read(),v=read(),
        Edge[u].emplace_back(v),
        Edge[v].emplace_back(u);
    dfs(1,0),solve(1,n);
    for(int i=1;i<=n;++i)
        printf("%lld ",ans[i]);
    return 0;
}
posted @   _Famiglistimo  阅读(118)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2021-02-13 整除分块详解
点击右上角即可分享
微信分享提示