zoukankan      html  css  js  c++  java
  • 【题解】Lomsat gelral [CF600E]

    【题解】Lomsat gelral [CF600E]

    【前言】

    写完 ( ext{Dsu on tree}) 后大致浏览了网上的题解,常见做法有以下几种:

    • ( ext{Dsu on tree})(占大多数,毕竟是板子)

    • 线段树合并(空间巨大)

    • (O(nsqrt{n}logn))( ext{DFS})(+) (sb) 暴力莫队(时间巨大)

    • (O(nsqrt{n}))( ext{DFS})(+) 回滚莫队(效率一般)

    但就是没找到一篇 ( ext{DFS})(+) 分治,让我来做全网第一篇吧(只是我没有找到,希望不要打脸吧)。

    【分析】

    子树查询转到序列上后其本质是一系列的区间查询,我们知道,要想用分治是需要满足一定单调性的,那么这些区间是否有我们想要的性质呢?

    先给出一些定义:

    • (size(x)) 表示 (|subtree(x)|),即以 (x) 为根的子树大小。

    • (dfn(x)) 表示节点 (x)( ext{DFS}) 序。

    • (idx(i)) 表示 ( ext{DFS})(i) 所对应的节点编号,满足 (dfn(idx(i))=i, idx(dfn(x))=x)

    • (Rdfn(i)) 表示 (i+size(idx(i))-1),即 ( ext{DFS})(i) 所对应的的节点子树中最大的 ( ext{DFS}) 序。

    【引理】

    抛结论
    (i'<i),若存在一个 (j) 满足 (i leqslant j leqslant Rdfn(i))(i' leqslant j leqslant Rdfn(i')),那么 一定有 (Rdfn(i') geqslant Rdfn(i))
    (按照 ( ext{YudeS}) 巨佬所说,穿过 (j) 的区间有互相包含的关系,放在此处即是区间 ([i,Rdfn(i)]) 被包含于 ([i',Rdfn(i')]) 中 )。

    其实很简单,稍想一下就明白了。

    证明
    由给出的两个条件可知 (idx(j) in subtree(idx(i)))(idx(j) in subtree(idx(i'))),所以 (idx(i),idx(i')) 均为(idx(j)) 的祖先节点。
    又因为 (i'<i),且任意一个节点 (x) 的所有祖先都在从根到 (x) 的简单路径上,所以 (idx(i')) 应为 (idx(i)) 的祖先节点,于是有 (Rdfn(i') geqslant Rdfn(i))

    【算法实现】

    回到这道题,有了上面那个性质,用分治已经很显然了吧,对于一层 ((L,mid,R)) 扫一遍计算出:满足 (L leqslant i leqslant mid)(mid+1 leqslant Rdfn(i) leqslant R) 的所有 (ans[i])

    时间复杂度为:(O(nlogn))

    核心操作就一个分治函数,好想又好写,居然没人用....

    像这种 (dot) 的题应该都可以用 ( ext{DFS})(+) 回滚莫队/分治 搞吧,(insert) 函数都不需要改,时间复杂度和分治基本一样(蒟蒻瞎口胡,可信度极低

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=1e5+3;
    int o,n,m,x,y,t,tmp,dfn_O,A[N],Q[N],cnt[N],dfn[N],idx[N],size[N],head[N];LL ans,Ans[N];
    struct QAQ{int to,next;}a[N<<1];
    inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    inline void dfs(Re x,Re fa){//预处理dfn序
        idx[dfn[x]=++dfn_O]=x,size[x]=1;
        for(Re i=head[x],to;i;i=a[i].next)
            if((to=a[i].to)!=fa)dfs(to,x),size[x]+=size[to];
    }
    inline void CL(){//清空贡献,从zero开始
        while(t)cnt[Q[t--]]=0;ans=tmp=0;
    }
    inline void insert(Re x){//加入点x的贡献
        ++cnt[Q[++t]=A[x]];
        if(cnt[A[x]]>tmp)tmp=cnt[ans=A[x]];
        else if(cnt[A[x]]==tmp)ans+=A[x];
    }
    inline void sakura(Re L,Re R){//分治解决(L,R)
        if(L==R){if(size[idx[L]]==1)Ans[idx[L]]=A[idx[L]];return;}
        Re mid=L+R>>1;
        sakura(L,mid),sakura(mid+1,R);//递归解决下面的
        Re p=mid;CL();//搞一个指针p
        for(Re i=mid,j;i>=L&&(j=i+size[idx[i]]-1)<=R;--i){//当j=Rdfn(i)大于R时就可以结束了
            insert(idx[i]);
            if(j<=mid)continue;//只解决对于j>mid的部分
            while(p<j)insert(idx[++p]);//由性质可知满足大于mid的那部分j是单调递增的,不断移动指针p即可
            Ans[idx[i]]=ans;//获得答案
        }
    }
    int main(){
    //  freopen("123.txt","r",stdin);
        in(n),m=n-1;
        for(Re i=1;i<=n;++i)in(A[i]);
        while(m--)in(x),in(y),add(x,y),add(y,x);
        dfs(1,0),sakura(1,n);
        for(Re i=1;i<=n;++i)printf("%lld ",Ans[i]);
    }
    

    【参考资料】

  • 相关阅读:
    BUUCTF [XMAN2018排位赛]四道misc题汇总
    祥云杯2020 Misc题解
    win10更换pip源
    BUUCTF N1BOOK配套题目
    kali下docker安装教程
    湖湘杯2020 Misc题解
    7号夺宝1元购iPhone6s 1元众筹怎么玩
    html5 的服务器推送 Server-sent Events和 websocket这两个是不是同一个东西,是两个不同的?
    WebSocket 是什么原理?为什么可以实现持久连接?
    使用HTML5的十大原因
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/12336327.html
Copyright © 2011-2022 走看看