• CF1120D Power Tree


    题意简述

    给你一棵有根树,定义叶子为度数为1的点。

    你可以以$ w_x (的代价控制)x(点。选择控制之后可以给它的子树里的叶子加 上)t (t in Z )$。

    你要以最小的总代价使得:另一个人在叶子上任意放数,你都可以把它
    们都变成0。

    最后输出最小的总代价,以及有多少点可能被控制,以及每个可能被控制的点的编号

    思路索引

    首先,我们可以把所有的叶子节点按照 dfs序 抽象成一个序列

    接下来,我们可以很神奇的发现,每一个点就对应着一个区间这不是废话吗

    然后,选择某个区间后,我们就可以对它进行区间加的操作

    既然是区间操作,肯定是不方便的,然后就很自然的想到了差分哪里自然了

    若点(x)对应区间([l,r]),那么,我们控制点x,就等同于在(l)(+t),在(r+1)(-t)(因此,我们需要虚构出一个新的叶子节点,以保证不会爆掉)

    我们观察一下这个序列,发现如果原数组均为0,则差分数组也均为0

    所以说,我们可以在(l)(r+1)之间连一条边权为(w_x)的边,我们可以在这条边的一端加上一个数,而在另一端减去一个相同的数

    我们发现,若所有叶子都联通,那么因为差分数组的和为0,所以我们必然能将每一个点都变成0

    求一遍最小生成树即可

    代码实现

    //``` 
    #include<bits/stdc++.h>
    #define ll long long
    #define now edge[i].v
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    using namespace std;
    const int SZ=2e5+7;
    ll ans;
    int cnt;
    int L,R;
    int u,v;
    int n,T;
    int w[SZ];
    int fa[SZ];
    int sz[SZ];
    bool vis[SZ];
    int head[SZ];
    bool f[SZ];
    int l[SZ],r[SZ];
    struct wxp{
        int v,nxt;
    }edge[SZ<<1];
    struct pb{
        int u,v,w,o;
    }E[SZ];
    bool cmp(pb p1,pb p2){
        return p1.w<p2.w;
    }
    int getfa(int x){
        return fa[x]==x?x:fa[x]=getfa(fa[x]);
    }
    void add(int u,int v){
        edge[++cnt]=(wxp){v,head[u]};
        head[u]=cnt;
    }
    void dfs(int x){
        sz[x]=1;
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].nxt)
        if(!vis[now]){
            dfs(now);
            sz[x]+=sz[now];
            l[x]=min(l[x],l[now]);
            r[x]=max(r[x],r[now]);
        }
        if(sz[x]==1) l[x]=r[x]=++T;
        E[x]=(pb){l[x],r[x]+1,w[x],x};
    }
    int main(){
        scanf("%d",&n);
        rep(i,1,n) scanf("%d",&w[i]);
        rep(i,1,n-1){
            scanf("%d%d",&u,&v);
            add(u,v),add(v,u);
        }
        memset(l,0x3f,sizeof(l));
        dfs(1);
        sort(E+1,E+n+1,cmp);
        rep(i,1,T+1) fa[i]=i;
        int sum=0;
        for(L=1;L<=n;L=R+1){
            R=L;
            while(E[R+1].w==E[L].w&&R<n) R++;
            rep(i,L,R){
                u=E[i].u,v=E[i].v;
                if(getfa(u)!=getfa(v)) f[E[i].o]=1,sum++;
            }
            rep(i,L,R){
                u=E[i].u,v=E[i].v;
                if(getfa(u)!=getfa(v)){
                    ans+=1ll*E[i].w;
                    fa[fa[u]]=fa[v];
                }
            }
        }
        printf("%I64d %d
    ",ans,sum);
        rep(i,1,n) if(f[i]) printf("%d ",i);
    } 
    
  • 相关阅读:
    Win7 IIS FTP
    (转)Windows平台下git中文乱码的问题
    (转)如何在MySql中记录SQL日志(例如Sql Server Profiler)
    (转)Mysql 使用
    Xcode 快捷键
    (转)xcode 4.2 新建工程模板详解
    解决apache的the requested operation has failed
    ANDROID 获取SD卡剩余容量
    (转)struct tm 的应用 了解strtok应用
    (转)Ubuntu建立PHP服务器(apache+php+mysql)
  • 原文地址:https://www.cnblogs.com/river-flows-in-you/p/10596821.html
Copyright © 2020-2023  润新知