• CF1120D Power Tree(构造题,差分,最小生成树)


    很有趣的一道题。

    首先可以对每个叶子进行编号。按照DFS到的顺序即可。(假设从 $1$ 到 $k$)

    然后对每个点求出它管辖的所有叶子的编号。因为是DFS序所以这一定是个区间。设点 $u$ 的这个区间是 $[l_u,r_u]$。

    区间加操作,考虑差分,那么每个点的操作就变成了 $l_u$ 加一个数,$r_u+1$ 减一个数。(此时也要考虑 $k+1$)

    那么题目要求就变成了所有数都变成 $0$。

    感受一下,把 $(l_u,r_u+1,c_u)$ 看做一条带权边,那么当且仅当选择的边构成连通图时满足要求。

    那么就变成最小生成树了。

    时间复杂度 $O(nlog n)$。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=200020;
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline int read(){
        int x=0,f=0;char ch=getchar();
        while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return f?-x:x;
    }
    struct edge{
        int u,v,w,id;
        bool operator<(const edge &e)const{
            return w<e.w;
        }
    }e[maxn];
    int n,c[maxn],el,head[maxn],to[maxn*2],nxt[maxn*2],el2;
    int lft[maxn],rig[maxn],dfn[maxn],dfs_clock,ccc,fa[maxn],at[maxn],sss[maxn],al;
    bool good[maxn];
    ll ans;
    inline void add(int u,int v){
        to[++el]=v;nxt[el]=head[u];head[u]=el;
    }
    int getfa(int x){
        return x==fa[x]?x:fa[x]=getfa(fa[x]);
    }
    void dfs(int u,int f){
        dfn[u]=++dfs_clock;
        lft[u]=n+1;rig[u]=0;
        for(int i=head[u];i;i=nxt[i]){
            int v=to[i];
            if(v==f) continue;
            dfs(v,u);
            lft[u]=min(lft[u],lft[v]);
            rig[u]=max(rig[u],rig[v]);
        }
        if(!rig[u]) lft[u]=rig[u]=++ccc;
    }
    int main(){
        n=read();
        FOR(i,1,n) c[i]=read();
        FOR(i,1,n-1){
            int u=read(),v=read();
            add(u,v);add(v,u);
        }
        dfs(1,0);
        FOR(i,1,n) e[++el2]=(edge){lft[i],rig[i]+1,c[i],i};
        sort(e+1,e+el2+1);
        FOR(i,1,ccc) fa[i]=i;
        FOR(i,1,el2){
            int j=i;
            while(j<=el2 && e[j].w==e[i].w) j++;
            j--;
            FOR(k,i,j){
                int u=e[k].u,v=e[k].v;
                u=getfa(u);v=getfa(v);
                if(u!=v) good[e[k].id]=true,al++;
            }
            FOR(k,i,j){
                int u=e[k].u,v=e[k].v;
                u=getfa(u);v=getfa(v);
                if(u!=v) fa[u]=v,ans+=e[k].w;
            }
            i=j;
        }
        cout<<ans<<" "<<al<<endl;
        FOR(i,1,n) if(good[i]) printf("%d ",i);
    }
    View Code
  • 相关阅读:
    .cu文件属性中没有“CUDA C/C++”的原因
    QT QGraphicsView 在鼠标点击处进行放大缩小
    VS2017+Qt使用QChartsView过程中遇到的问题
    QString与char*的相互转换
    QT -- 对话框获取文件夹下所选图像名称
    Qt -- 获取文件夹中的文件/文件夹名字
    C/C++取数据中高8位,低8位,合成新数据
    C/C++中的位运算
    求解逆矩阵的常用三种方法
    Javascript定义类(class)的三种方法
  • 原文地址:https://www.cnblogs.com/1000Suns/p/10922629.html
Copyright © 2020-2023  润新知