zoukankan      html  css  js  c++  java
  • Atcoder beginner contest 163 f path pass i

    传送门:https://atcoder.jp/contests/abc163/tasks/abc163_f

    题目大意:一颗n个节点的树,每个节点有一个颜色。求对每一个颜色,至少经过一个该颜色节点的简单路径数量。

      分析:虽然有O(n)的做法,但是这里还是贴一下虚树的做法。虚树的做法大概是:对每一种颜色建立虚树,对于每一个标记好的节点,分别统计其子树的非标记节点联通块大小,总数减去这样的情况。这里是通过子树大小减去子树中标记节点的子树大小来统计的。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline int read(){
        int res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    #define go(e,u) for(int e=head[u];e;e=Next[e])
    int to[MAXN<<1],Next[MAXN<<1],head[MAXN],tol;
    
    void add_edge(int u,int v){
        Next[++tol]=head[u];to[tol]=v;head[u]=tol;
        Next[++tol]=head[v];to[tol]=u;head[v]=tol;
    }
    
    #define gov(e,u) for(int e=headv[u];e;e=Nextv[e])
    int tov[MAXN<<1],Nextv[MAXN<<1],headv[MAXN],tolv;
    
    void add_edgev(int u,int v){
        Nextv[++tolv]=headv[u];tov[tolv]=v;headv[u]=tolv;
    }
    
    int n, col[MAXN];
    
    vector<int> nodes[MAXN];
    
    int dfn[MAXN], R[MAXN], dfncnt;
    int up[MAXN][25], dep[MAXN], st[MAXN], top, sz[MAXN];
    int mark[MAXN];
    
    LL ans;
    
    void dfs(int u, int f){
        sz[u]=1;
        dfn[u]=++dfncnt;
    
        for(int i=0;up[u][i];++i)up[u][i+1]=up[up[u][i]][i];
    
        go(e,u){
            int v=to[e];
            if(v==f)continue;
            up[v][0]=u;
            dep[v]=dep[u]+1;
            dfs(v,u);
            sz[u]+=sz[v];
        }
        R[u]=dfncnt;
    }
    
    int getLCA(int u, int v){
        if(dep[u]<dep[v])swap(u,v);
    
        for(int i=20;i>=0;--i){
            if(dep[up[u][i]]>=dep[v]){
                u=up[u][i];
            }
        }
    
        if(u==v)return u;
    
        for(int i=20;i>=0;--i){
            if(up[u][i]!=up[v][i]){
                u=up[u][i];
                v=up[v][i];
            }
        }
    
        return up[u][0];
    }
    
    bool cmp(int x, int y){
        return dfn[x]<dfn[y];
    }
    
    bool cmp2(PII x, PII y){//未排序,wa
        return x.fi<y.fi;
    }
    
    LL dfs1(int u){
        LL s=0;
    
        vector<PII> num;
        gov(e,u){
            int v=tov[e];
            LL t=dfs1(v);
            s+=t;
            if(mark[u]) num.PB(MP(dfn[v],t));
        }
    
        sort(all(num),cmp2);
    
        if(mark[u]){
            int idx=0;
            go(e,u){
                int v=to[e];
                if(v==up[u][0])continue;
                int cc=0;
                while(idx<SZ(num)&&num[idx].fi>=dfn[v]&&num[idx].fi<=R[v]){
                    cc+=num[idx].sd;
                    ++idx;
                }
    
                ans-=1ll*(sz[v]-cc)*(sz[v]-cc+1)/2;
            }
        }
    
        if(u==1&&!mark[u]){
            LL num=sz[1]-s;
            ans-=1ll*num*(num+1)/2;
        }
    
        if(mark[u])return sz[u];
        else return s;
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;++i){
            col[i]=read();
            nodes[col[i]].PB(i);
        }
    
        for(int i=1;i<n;++i){
            int u=read(),v=read();
            add_edge(u,v);
        }
    
        dep[1]=1;
        dfs(1,0);
        for(int color=1;color<=n;++color){
            if(!SZ(nodes[color])){
                cout<<0<<endl;
                continue;
            }
    
            ans=1ll*n*(n+1)/2;
            sort(all(nodes[color]),cmp);
    
            //建立虚树
            st[top=1]=1;headv[1]=0;tolv=0;
            for(int i=0;i<SZ(nodes[color]);++i){
                int nn=nodes[color][i];
                mark[nn]=1;
                if(nn==1)continue;
    
                int l=getLCA(st[top],nn);
    
                if(l!=st[top]){
                    while(dfn[l]<dfn[st[top-1]]){
                        add_edgev(st[top-1],st[top]);
                        --top;
                    }
                    if(dfn[l]>dfn[st[top-1]]){
                        headv[l]=0;add_edgev(l,st[top]);st[top]=l;
                    }else{
                        add_edgev(l,st[top--]);
                    }
                }
                headv[nn]=0;st[++top]=nn;
            }
    
            for(int i=1;i<top;++i){
                add_edgev(st[i],st[i+1]);
            }
    
            dfs1(st[1]);
            cout<<ans<<endl;
            for(int i=0;i<SZ(nodes[color]);++i)mark[nodes[color][i]]=0;
        }
    
        return 0;
    }
    View Code

    BTW,O(n)的做法。

    #include<bits/stdc++.h>
    
    #define all(x) x.begin(),x.end()
    #define fi first
    #define sd second
    #define lson (nd<<1)
    #define rson (nd+nd+1)
    #define PB push_back
    #define mid (l+r>>1)
    #define MP make_pair
    #define SZ(x) (int)x.size()
    
    using namespace std;
    
    typedef long long LL;
    
    typedef vector<int> VI;
    
    typedef pair<int,int> PII;
    
    inline LL read(){
        LL res=0, f=1;char ch=getchar();
        while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
        return res*f;
    }
    
    const int MAXN = 200'005;
    
    const int MOD = 1000000007;
    
    void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
    int mulmod(int a, int b){return 1ll*a*b%MOD;}
    
    template<typename T>
    void chmin(T& a, T b){if(a>b)a=b;}
    
    template<typename T>
    void chmax(T& a, T b){if(b>a)a=b;}
    
    LL n;
    
    LL sz[MAXN], sum[MAXN], ans[MAXN];
    LL col[MAXN];
    
    #define go(e,u) for(int e=head[u];e;e=Next[e])
    int to[MAXN<<1],Next[MAXN<<1],head[MAXN],tol;
    
    void add_edge(int u,int v){
        Next[++tol]=head[u];to[tol]=v;head[u]=tol;
        Next[++tol]=head[v];to[tol]=u;head[v]=tol;
    }
    
    LL calc(LL x){return x*(x+1)/2;}
    
    void dfs(int u,int f){
        int c=col[u];
        sz[u]=1;LL o=sum[c];
        go(e,u){
            int v=to[e];
            if(v==f)continue;
            LL t=sum[c];
            dfs(v,u);
            ans[c]-=calc(sz[v]-(sum[c]-t));
            sz[u]+=sz[v];
        }
        sum[col[u]]=o+sz[u];
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;++i)col[i]=read(),ans[i]=n*(n+1)/2;
    
        for(int i=1,u,v;i<n;++i){
            u=read();
            v=read();
            add_edge(u,v);
        }
    
        dfs(1,0);
    
        for(int i=1;i<=n;++i){
            LL t=n-sum[i];
            ans[i]-=calc(t);
            cout<<ans[i]<<endl;
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    ubuntu挂载群晖共享文件
    200. 岛屿数量_中等_不再记笔记了
    733. 图像渲染_简单_矩阵
    46. 全排列_中等_模拟
    37. 解数独_困难_矩阵
    1041. 困于环中的机器人_中等_模拟
    946. 验证栈序列
    415. 字符串相加_简单_模拟
    164. 最大间距_数组_困难
    215. 数组中的第K个最大元素_中等_数组
  • 原文地址:https://www.cnblogs.com/JohnRan/p/12773872.html
Copyright © 2011-2022 走看看