• Codeforces Round #378 (Div. 2)F


    http://codeforces.com/contest/733/problem/F

    题意:给你一些城市和一些路,每条路有不满意程度和每减少一点不满意程度的花费,给出最大花费,要求找出花费小于s的最小生成树中最小的不满意程度

    题解:首先明确的是肯定只删除一条路然后其他的找最小生成树即可,但是直接搞复杂度O(m*mlogm)所以先prim扣出一颗最小生成树,然后枚举所有边删这条边,如果在最小生成树上,直接减到贡献即可,如果不在最小生成树上,那么加上这条边,树肯定有环了,我们用lca暴力的扣出这个环最大的不满意程度的那条边,删掉即可,然后算贡献。总的复杂度是O(mlogm+m*logn)

    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    //#pragma GCC optimize("unroll-loops")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000009
    #define C 0.5772156649
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    #define cd complex<double>
    #define ull unsigned long long
    #define base 1000000000000000000
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    
    using namespace std;
    
    const double g=10.0,eps=1e-12;
    const int N=200000+10,maxn=1000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
    
    struct edge{
        int u,v,id;ll w,c;
        bool operator <(const edge&rhs)const{
            return w<rhs.w;
        }
    }e[N];
    int father[N],fa[20][N],id[20][N],n,m,dep[N];
    ll ma[20][N],s;
    bool vis[N];
    vector<edge>v[N];
    int Find(int x)
    {
        return father[x]==x?x:father[x]=Find(father[x]);
    }
    bool cmp(edge a,edge b)
    {
        return a.id<b.id;
    }
    ll prim()
    {
        for(int i=1;i<=m;i++)scanf("%lld",&e[i].w);
        for(int i=1;i<=m;i++)scanf("%lld",&e[i].c);
        for(int i=1;i<=m;i++)
        {
            e[i].id=i;
            scanf("%d%d",&e[i].u,&e[i].v);
        }
        for(int i=1;i<=n;i++)father[i]=i;
        sort(e+1,e+1+m);
        ll sum=0;
        for(int i=1;i<=m;i++)
        {
            int x=e[i].u,y=e[i].v;
            int fx=Find(x),fy=Find(y);
            if(fx!=fy)
            {
                father[fx]=fy;
                vis[e[i].id]=1;
                sum+=e[i].w;
            }
        }
        sort(e+1,e+1+m,cmp);
        for(int i=1;i<=m;i++)
        {
            if(vis[i])
            {
                v[e[i].u].pb(e[i]);
                swap(e[i].u,e[i].v);
                v[e[i].u].pb(e[i]);
            }
        }
        return sum;
    }
    void dfs(int u,int f,int d)
    {
        dep[u]=d;
        for(int i=0;i<v[u].size();i++)
        {
            int x=v[u][i].v;
            if(x!=f)
            {
                fa[0][x]=u;
                ma[0][x]=v[u][i].w;
                id[0][x]=v[u][i].id;
                dfs(x,u,d+1);
            }
        }
    }
    void init()
    {
        dfs(1,-1,0);
    //    for(int i=1;i<=n;i++)printf("%d %lld %d 
    ",fa[0][i],ma[0][i],id[0][i]);
        for(int i=1;i<20;i++)
        {
            for(int j=1;j<=n;j++)
            {
                fa[i][j]=fa[i-1][fa[i-1][j]];
                if(ma[i-1][fa[i-1][j]]>ma[i-1][j])
                {
                    ma[i][j]=ma[i-1][fa[i-1][j]];
                    id[i][j]=id[i-1][fa[i-1][j]];
                }
                else
                {
                    ma[i][j]=ma[i-1][j];
                    id[i][j]=id[i-1][j];
                }
            }
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]>dep[y])swap(x,y);
        int ans=0;ll maxx=0;
        for(int i=0;i<20;i++)
        {
            if((dep[y]-dep[x])>>i&1)
            {
                if(maxx<ma[i][y])
                {
                    maxx=ma[i][y];
                    ans=id[i][y];
                }
                y=fa[i][y];
            }
        }
        if(x==y)return ans;
        for(int i=19;i>=0;i--)
        {
            if(fa[i][x]!=fa[i][y])
            {
                if(maxx<ma[i][x])
                {
                    maxx=ma[i][x];
                    ans=id[i][x];
                }
                if(maxx<ma[i][y])
                {
                    maxx=ma[i][y];
                    ans=id[i][y];
                }
                x=fa[i][x];
                y=fa[i][y];
            }
        }
        if(maxx<ma[0][x])
        {
            maxx=ma[0][x];
            ans=id[0][x];
        }
        if(maxx<ma[0][y])
        {
            maxx=ma[0][y];
            ans=id[0][y];
        }
        return ans;
    }
    void solve(ll sum)
    {
        ll ans=1e18,pos;
        for(int i=1;i<=m;i++)
        {
            if(vis[i])
            {
                if(ans>sum-s/e[i].c)
                {
                    ans=sum-s/e[i].c;
                    pos=i;
                }
            }
            else
            {
                int ff=lca(e[i].u,e[i].v);
                if(ans>sum-e[ff].w+e[i].w-s/e[i].c)
                {
                    ans=sum-e[ff].w+e[i].w-s/e[i].c;
                    pos=i;
                }
            }
        }
        if(!vis[pos])vis[lca(e[pos].u,e[pos].v)]=0;
        printf("%lld
    ",ans);
        for(int i=1;i<=m;i++)
        {
            if(pos==i)printf("%d %d
    ",i,e[i].w-s/e[i].c);
            else if(vis[i])printf("%d %d
    ",i,e[i].w);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        ll sum=prim();
        scanf("%lld",&s);
    //    for(int i=1;i<=n;i++)
    //    {
    //        for(int j=0;j<v[i].size();j++)
    //        {
    //            printf("%d %d %d %lld %lld
    ",v[i][j].u,v[i][j].v,v[i][j].id,v[i][j].w,v[i][j].c);
    //        }
    //        puts("");
    //    }
        init();
        solve(sum);
        return 0;
    }
    /***********************
    3 3
    1 1 1000
    5 5 2
    2 1
    3 1
    3 2
    2
    ***********************/
    View Code
  • 相关阅读:
    declare set声明注意
    Winform 的dadagridview控件的修改操作
    VS2010,VS2008,VS2005;工程之间的转换
    C#程序跨平台?
    上网黑色护眼,设置浏览器黑色风格
    AutoCompleteSource从文件里读取自动填充内容
    两个checkbox的控件控制操作只能选其一
    《博客园精华集CLR/C#分册》第三轮筛选结果 转载
    TransactSQL 示例 查询某个数据库内的所有表的记录行数及其总和
    EF 4.1中内部经常提交的 exec sp_reset_connection 的用途原来是为了重用池中的连接
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/8904802.html
Copyright © 2020-2023  润新知