• NC14419 线路规划(最小生成树+倍增)


    本来是一道最小生成树的问题,但是因为边数过多,因此考虑优化

    观察到这是区间信息,可以联想到使用倍增算法,将区间变成2进制,从大长度不断往下,每一层做一下最小生成树,目的是排除一些不需要的连边。用队列保存有用的

    这样到0的时候做的最小生成树就是答案。这样的复杂度保证是,我们只会做log层,并且每层的队列中的信息最多是n,因此是nlogn

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=3e5+10;
    const int mod=1e9+7;
    int p[N][31];
    int f[N][31];
    ll sum[N],tot[N];
    int n,m;
    struct node{
        int a,b,k,w;
    }s[N];
    queue<node> q1[30],q2[30];
    bool cmp(node a,node b){
        return a.w<b.w;
    }
    int find(int x,int i){
        if(p[x][i]!=x){
            p[x][i]=find(p[x][i],i);
        }
        return p[x][i];
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m;
        int i,j;
        int pp=log2(n)+1;
        f[1][0]=1;
        for(i=2;i<=n;i++){
            int x;
            cin>>x;
            f[i][0]=x;
        }
        for(i=1;i<=pp;i++){
            for(j=1;j<=n;j++){
                f[j][i]=f[f[j][i-1]][i-1];
            }
        }
        for(i=1;i<=n;i++){
            for(j=0;j<=30;j++){
                p[i][j]=i;
            }
        }
        for(i=1;i<=n;i++){
            tot[i]=1;
            sum[i]=0;
        }
        for(i=1;i<=m;i++){
            cin>>s[i].a>>s[i].b>>s[i].k>>s[i].w;
        }
        sort(s+1,s+1+m,cmp);
        for(i=1;i<=m;i++){
            int cnt=s[i].k;
            node tmp=s[i];
            while(cnt>0){
                int pos=floor(log2(1.0*cnt));
                q1[pos].push(tmp);
                tmp.a=f[tmp.a][pos];
                tmp.b=f[tmp.b][pos];
                cnt-=(1<<pos);
            }
        }
        for(i=pp;i>=0;i--){
            while(!q1[i].empty()||!q2[i].empty()){
                node tmp;
                if(q1[i].size()&&q2[i].size()){
                    auto tmp1=q1[i].front();
                    auto tmp2=q2[i].front();
                    if(tmp1.w<=tmp2.w){
                        tmp=tmp1;
                        q1[i].pop();
                    }
                    else{
                        tmp=tmp2;
                        q2[i].pop();
                    }
                }
                else if(q1[i].size()){
                    auto tmp1=q1[i].front();
                    q1[i].pop();
                    tmp=tmp1;
                }
                else{
                    tmp=q2[i].front();
                    q2[i].pop();
                }
                int pa=find(tmp.a,i),pb=find(tmp.b,i);
                if(pa!=pb){
                    if(i==0){
                        tot[pb]+=tot[pa];
                        p[pa][0]=pb;
                        sum[pb]+=sum[pa]+tmp.w;
                    }
                    else{
                       p[pa][i]=pb;
                       q2[i-1].push(tmp);
                       tmp.a=f[tmp.a][i-1];
                       tmp.b=f[tmp.b][i-1];
                       q2[i-1].push(tmp);
                    }
                }
            }
        }
        ll ans=1e18;
        int mx=0;
        for(i=1;i<=n;i++){
            if(p[i][0]==i){
                if(tot[i]>mx){
                    mx=tot[i];
                    ans=sum[i];
                }
                else if(tot[i]==mx){
                    ans=min(ans,sum[i]);
                }
            }
        }
        cout<<mx<<" "<<ans<<endl;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    Oracle
    CCF 201609-5 祭坛
    prometheus同时执行多个查询
    压力测试 Apache ab
    kubernetes reference
    python 深拷贝
    [ argo workflow ]
    django orm 改动数据库中已存在的表(添加、删除、修改表字段)migrations
    内存压力测试命令
    django 未成功初始化自定义表单
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13971401.html
Copyright © 2020-2023  润新知