zoukankan      html  css  js  c++  java
  • 【codeforces 733F】Drivers Dissatisfaction

    【题目链接】:http://codeforces.com/problemset/problem/733/F

    【题意】

    给你n个点m条边;
    让你从中选出n-1条边;
    形成一个生成树;
    (即让n个点都联通);
    然后,你有S的预算;
    每次可以选择一条边i,然后花费ci的预算,把这条边的权值递减1;
    (边一开始的权值为wi);
    问你最后的最小生成树是多少;

    【题解】

    /*
        肯定是找某一条边一直减(ci最小的那一个,因为代价最小,又都是减少1);
        把m条边按照w升序排;
        做个最小生成树;
        把最小生成树里面c最小的那条边一直减就好,这个作为ans1;
        然后在这个最小生成树上写个dfs,
        搞出来每个点上面的第2^i个节点是谁,以及这个点到这个点上面的第2^i个点之间,最大的w是哪条边.
        然后枚举所有的非树边,这里的非树边,它的c的值一定要小于最小生成树里面的树边的最小的c值;
        这样它才有可能成为那条一直减小的边;然后最后比最小生成树里面的某条边边权来得小;
        假如非树边的两个点是u和v;
        则如果你要把u-v这条边加到MST里面的话,则必然要在从u到v的路径上选一条边删掉;
        删掉的边应是最大的那条边.(记录这条边是什么,删掉之后下次如果还要删的话,得还原)
        具体方式就是找到u和v的LCA;
        然后从u到lca的路径中找最大w的边;
        然后从v到lca的路径总找最大w的边;
        取两个边的w的较大者;
        然后把这条边删掉;
        然后把这条枚举的边加进去;一直减;然后更新答案;
    */


    【Number Of WA

    0

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define ms(x,y) memset(x,y,sizeof x)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int M = 2e5+100;
    const int INF = 21e8;
    
    struct abc
    {
        int w,c,u,v,id;
    };
    
    int n,m,f[M],b[M],fa[M][22],d[M][22],deep[M],C,num,bin[22],bb[M],pri[M];
    LL tot,ans,S;
    abc a[M];
    vector <pii> g[M];
    
    int ff(int x)
    {
        if (f[x]==x)
            return x;
        else
            return f[x] = ff(f[x]);
    }
    
    int maxw(int x,int y)
    {
        if (a[x].w>a[y].w)
            return x;
        else
            return y;
    }
    
    void dfs(int x)
    {
        rep1(i,1,20)
            fa[x][i] = fa[fa[x][i-1]][i-1];
        rep1(i,1,20)
            d[x][i] = maxw(d[x][i-1],d[fa[x][i-1]][i-1]);
        for (pii temp:g[x])
        {
            int y = temp.fi,w = temp.se;
            if (y==fa[x][0]) continue;
            fa[y][0] = x,d[y][0] = w;
            deep[y] = deep[x]+1;
            dfs(y);
        }
    }
    
    int lcq(int x,int y)
    {
        if (deep[x]<deep[y])
            swap(x,y);
        //deep[x]>=deep[y];
        int temp = deep[x]-deep[y];
        rep1(i,0,20)
            if (temp&bin[i])
                x = fa[x][i];
        //deep[x]==deep[y];
        rep2(i,20,0)
            if (fa[x][i]!=fa[y][i])
                x = fa[x][i],y = fa[y][i];
        return x==y?x:fa[x][0];
    }
    
    int query(int x,int y)
    {
        //deep[x]>=deep[y]
        int temp = deep[x]-deep[y];
        int ret = 0;
        rep1(i,0,20)
            if (temp&bin[i])
            {
                ret = maxw(ret,d[x][i]);
                x = fa[x][i];
            }
        return ret;
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        ios::sync_with_stdio(false),cin.tie(0);//scanf,puts,printf not use
        //init??????
        bin[0] = 1;
        rep1(i,1,20) bin[i] = bin[i-1]<<1;
        cin >> n >> m;
        rep1(i,1,m) cin >> a[i].w;
        rep1(i,1,m) cin >> a[i].c;
        rep1(i,1,m)
        {
            cin >> a[i].u >> a[i].v;
            a[i].id = i;
        }
        cin >>S;
        sort(a+1,a+1+m,[&](abc a,abc b) {return a.w<b.w;});
        C = INF;
        rep1(i,1,n) f[i] = i;
        rep1(i,1,m)
        {
            int x = a[i].u,y = a[i].v;
            int r1 = ff(x),r2 = ff(y);
            if (r1!=r2)
            {
                f[r1] = r2;
                g[x].pb(mp(y,i));
                g[y].pb(mp(x,i));
                b[i] = 1;
                if (a[i].c<C)
                {
                    C = a[i].c;
                    num = i;
                }
                tot+=a[i].w;
            }
        }
        ans = tot-S/C;
        dfs(1);
        int dl = 0,prei = 0;
        rep1(i,1,m)
            if (a[i].c<C)
            {
                int x = a[i].u,y = a[i].v;
                int z = lcq(x,y);
                int tmp = maxw(query(x,z),query(y,z));
                LL temp = tot-a[tmp].w+a[i].w;
                temp-=S/a[i].c;
                if (temp<ans)
                {
                    b[dl] = 1;b[dl=tmp] = 0;
                    b[prei] = 0;prei = i;
                    num = i;b[i] = 1;
                    ans = temp;
                }
            }
        cout << ans << endl;
        rep1(i,1,m)
            if (b[i])
            {
                bb[a[i].id] = 1;
                if (num==i)
                    pri[a[i].id] = a[i].w-S/a[i].c;
                else
                    pri[a[i].id] = a[i].w;
            }
        rep1(i,1,m)
            if (bb[i])
                cout << i <<' '<<pri[i]<<endl;
        return 0;
    }
    
  • 相关阅读:
    什么是内存碎片
    java堆内存模型
    java内存模型
    java垃圾回收过程
    找出给定的一个字符串中最长的不重复子串,不重复子串即一个子串中不出现两个相同的字符
    学习tomcat(八)
    学习Redis(二)
    学习k8s(四)
    学习docker(三)
    学习MySql(一)
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626318.html
Copyright © 2011-2022 走看看