• CodeForces 733F Drivers Dissatisfaction


    最小生成树变形,倍增。

    每条边有权值$1$和权值$2$,要求构造最小生成树,有一条边可以选择权值$2$,其余边选择权值$1$。

    先对权值$1$求最小生成树,然后枚举每一条边用权值$2$去替换树中的边即可。

    寻找树上某条连权值最大的边,带修改的可以采用树链剖分;无修改的可以将树有根化,然后计算两点到公共祖先之间的权值最大的边,倍增预处理即可。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0);
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    template <class T>
    inline void read(T &x)
    {
        char c = getchar();
        x = 0;
        while(!isdigit(c)) c = getchar();
        while(isdigit(c))
        {
            x = x * 10 + c - '0';
            c = getchar();
        }
    }
    
    int n,m;
    struct Edge
    {
        int u,v;
        long long w1,w2;
        int id;
        int flag;
    }e[200010];
    long long S,MST;
    int f[200010],dep[200010];
    vector<int>T[200010];
    
    int to[200010][35];
    long long mx[200010][35];
    int idx[200010][35];
    
    int Find(int x)
    {
        if(x!=f[x]) f[x]=Find(f[x]);
        return f[x];
    }
    
    bool cmp(Edge a,Edge b) { return a.w1<b.w1; }
    bool cmp2(Edge a,Edge b) { return a.id<b.id; }
    
    void dfs(int fa,int x,int y,int eid)
    {
        f[x]=fa; dep[x]=y;
    
        if(x==1)
        {
            to[x][0]=-1;
            mx[x][0]=-1;
            idx[x][0]=-1;
        }
        else
        {
            to[x][0]=fa;
            mx[x][0]=e[eid].w1;
            idx[x][0]=eid;
        }
    
        for(int j=1;j<=30;j++)
        {
            if((1<<j)>dep[x]-1)
            {
                to[x][j]=-1;
                mx[x][j]=-1;
                idx[x][j]=-1;
                continue;
            }
    
            to[x][j]=to[to[x][j-1]][j-1];
            if(mx[x][j-1]>=mx[to[x][j-1]][j-1])
            {
                mx[x][j]=mx[x][j-1];
                idx[x][j]=idx[x][j-1];
            }
            else
            {
                mx[x][j]=mx[to[x][j-1]][j-1];
                idx[x][j]=idx[to[x][j-1]][j-1];
            }
        }
    
        for(int i=0;i<T[x].size();i++)
        {
            int id=T[x][i];
            int v;
            if(e[id].u==x) v=e[id].v;
            else v=e[id].u;
    
            if(f[v]!=0) continue;
    
            dfs(x,v,y+1,id);
        }
    }
    
    int F(int a,int b)
    {
        if(dep[a]<dep[b]) swap(a,b);
    
        long long MX=0; int res;
        if(dep[a]!=dep[b])
        {
            while(1)
            {
                int L=0,R=30,pos;
                while(L<=R)
                {
                    int mid=(L+R)/2;
                    if(to[a][mid]!=-1&&dep[to[a][mid]]>=dep[b]) L=mid+1,pos=mid;
                    else R=mid-1;
                }
    
                if(mx[a][pos]>=MX) MX=mx[a][pos], res=idx[a][pos];
    
                a=to[a][pos];
                if(dep[a]==dep[b]) break;
            }
        }
    
        if(a==b) return res;
    
        while(1)
        {
            if(f[a]==f[b])
            {
                if(mx[a][0]>=MX) MX=mx[a][0], res=idx[a][0];
                if(mx[b][0]>=MX) MX=mx[b][0], res=idx[b][0];
                break;
            }
    
            int L=0,R=30,pos;
            while(L<=R)
            {
                int mid=(L+R)/2;
                if(to[a][mid]!=to[b][mid]) L=mid+1,pos=mid;
                else R=mid-1;
            }
    
            if(mx[a][pos]>=MX) MX=mx[a][pos], res=idx[a][pos];
            if(mx[b][pos]>=MX) MX=mx[b][pos], res=idx[b][pos];
    
            a=to[a][pos];
            b=to[b][pos];
        }
    
        return res;
    }
    
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++) cin>>e[i].w1;
        for(int i=1;i<=m;i++) cin>>e[i].w2;
        for(int i=1;i<=m;i++) cin>>e[i].u>>e[i].v;
        cin>>S;
        for(int i=1;i<=m;i++) e[i].w2=e[i].w1-S/e[i].w2;
        for(int i=1;i<=m;i++) e[i].id=i,e[i].flag=0;
    
        sort(e+1,e+1+m,cmp);
    
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=m;i++)
        {
            int A=Find(e[i].u), B=Find(e[i].v);
            if(A==B) continue;
    
            f[A]=B; MST+=e[i].w1;
    
            e[i].flag=1;
            T[e[i].u].push_back(e[i].id);
            T[e[i].v].push_back(e[i].id);
        }
    
        sort(e+1,e+1+m,cmp2);
        memset(f,0,sizeof f); dfs(-1,1,1,-1);
    /*
        for(int i=1;i<=n;i++)
        {
            printf("%d -- fa:%d -- dep:%d
    ",i,f[i],dep[i]);
        }
    */
    
        int U,V; long long now=MST;
    
        for(int i=1;i<=m;i++)
        {
            int eid = F(e[i].u,e[i].v);
    
            if(MST-e[eid].w1+e[i].w2<=now)
            {
                now=MST-e[eid].w1+e[i].w2;
                U=eid; V=i;
            }
        }
    
        e[U].flag=0; e[V].flag=2;
    
        printf("%lld
    ",now);
        for(int i=1;i<=m;i++)
        {
            if(e[i].flag==0) continue;
            if(e[i].flag==1) printf("%d %lld
    ",i,e[i].w1);
            if(e[i].flag==2) printf("%d %lld
    ",i,e[i].w2);
        }
    
        return 0;
    }
  • 相关阅读:
    cron表达式详解(转载)
    Swagger 3.0使用教程(转载)
    springboot整合shiro-对密码进行MD5并加盐处理(十五)(转载)
    redis排序
    引用和指针的区别?
    测试策略
    主键、外键的作用,索引的优点与不足?
    您所熟悉的软件测试类型都有哪些?请试着分别比较这些不同的测试类型的区别与联系(如功能测试、性能测试……)
    UI测试测什么
    数据库,数据库管理系统,数据库系统三者的区别和练习?
  • 原文地址:https://www.cnblogs.com/zufezzt/p/6387444.html
Copyright © 2020-2023  润新知