zoukankan      html  css  js  c++  java
  • CF 786 E ALT

    CF 786 E ALT

    一个居民有两个选择:分配一只宠物,路上都有宠物

    一个守卫有两种选择:分配一只宠物,不分配宠物

    我们找一个原点,到每个居民都有一条边,表示是否给他宠物

    从每个居民向他路上的守卫连边

    守卫到汇点连边。

    居民到守卫的边容量是 $ infin $ ,所以现在达到的效果就是,要么一个居民被加边,要么一个居民连向守卫都被鸽。

    一个居民连向了 $ O(n) $ 个点啊!

    怎么优化?所以我们可以类似倍增 LCA 的方法,如果向一个点的第 $ j $ 个点连边,表示它向上跳 $ 2^k $ 个点那都连。最后边数是 $ mlog $ 。

    最小割怎么输出方案呢?我们从 $ S $ 开始 dfs 一次,最终一条边两端的点一个没有被跑到过一个被跑到过的话,这个边就加入边集。

    我觉得并不是非常好写。。(码力弱鸡)

    #include "iostream"
    #include "algorithm"
    #include "cstring"
    #include "cstdio"
    #include "vector"
    #include "queue"
    #include "cmath"
    using namespace std;
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mp make_pair
    #define MAXN 50006
    
    int cn = 2;
    const int inf = 0x3f3f3f3f;
    class maxFlow {
    public:
        typedef long long ll;
        std::queue<int> q;
        std::vector<int> head, cur, nxt, to, dep;
        std::vector<ll> cap;
    
        maxFlow(int _n = 0) { init(_n); }
        void init(int _n) {
            head.clear();
            head.resize(_n + 1, 0);
            nxt.resize(2);
            to.resize(2);
            cap.resize(2);
        }
        void init() { init(head.size() - 1); }
        int add(int u, int v, ll w) {
            nxt.push_back(head[u]);
            int x = ( head[u] = to.size() );
            to.push_back(v);
            cap.push_back(w);
            return x;
        }
        int Add(int u, int v, ll w) {
    //      printf("%d %d %d
    ",u,v,w);
            add(u, v, w);
            return add(v, u, 0);
        }
        void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
        bool bfs(int s, int t, int delta) {
            dep.clear();
            dep.resize(head.size(), -1);
            dep[s] = 0;
            q.push(s);
            while (!q.empty()) {
                int u = q.front();
                q.pop();
                for (int i = head[u]; i; i = nxt[i]) {
                    int v = to[i];
                    ll w = cap[i];
                    if (w >= delta && dep[v] == -1) {
                        dep[v] = dep[u] + 1;
                        q.push(v);
                    }
                }
            }
            return ~dep[t];
        }
        ll dfs(int u, ll flow, int t, int delta) {
            if (dep[u] == dep[t])
                return u == t ? flow : 0;
            ll out = 0;
            for (int& i = cur[u]; i; i = nxt[i]) {
                int v = to[i];
                ll w = cap[i];
                if (w >= delta && dep[v] == dep[u] + 1) {
                    ll f = dfs(v, std::min(w, flow - out), t, delta);
                    cap[i] -= f;
                    cap[i ^ 1] += f;
                    out += f;
                    if (out == flow)
                        return out;
                }
            }
            return out;
        }
        ll maxflow(int s, int t) {
            ll out = 0;
            ll maxcap = *max_element(cap.begin(), cap.end());
            for (ll delta = 1ll << int(log2(maxcap) + 1e-12); delta; delta >>= 1) {
                while (bfs(s, t, delta)) {
                    cur = head;
                    out += dfs(s, 0x7fffffffffffffffll, t, delta);
                }
            }
            return out;
        }
        ll getflow(int x) const { return cap[x << 1 | 1]; }
        int vis[3000000];
        void work( int u ) {
            vis[u] = 1;
            for( int i = head[u] ; i ; i = nxt[i] ) if( cap[i] ) {
                int v = to[i];
                if( !vis[v] ) work( v );
            }
        }
    } F ;
    
    int n , m;
    vector<int> G[MAXN];
    int g[MAXN][16] , p[MAXN][16] , dep[MAXN];
    int T[MAXN] , S[MAXN] , tt[MAXN] , bacs[3000000] , bact[3000000];
    void dfs( int u , int fa ) {
        for( int v : G[u] ) if( v != fa ) {
            dep[v] = dep[u] + 1;
            g[v][0] = u , p[v][0] = ++ cn;
            T[v] = F.Add( p[v][0] , 2 , 1 );
            for( int k = 1 ; k < 16 ; ++ k )
                if( g[g[v][k-1]][k-1] ) {
                    g[v][k] = g[g[v][k-1]][k-1];
                    p[v][k] = ++ cn;
                    F.Add( p[v][k] , p[v][k - 1] , inf );
                    F.Add( p[v][k] , p[g[v][k-1]][k-1] , inf );
                } else break;
            dfs( v , u );
        }
    }
    void link( int i , int u , int v ) { // id -> u~v
        if( dep[u] < dep[v] ) swap( u , v );
        for( int k = 15 ; k >= 0 ; -- k )
            if( dep[g[u][k]] >= dep[v] )
                F.Add( i , p[u][k] , inf ) , u = g[u][k];
        if( u == v ) return;
        for( int k = 15 ; k >= 0 ; -- k )
            if( g[u][k] != g[v][k] )
                F.Add( i , p[u][k] , inf ) , F.Add( i , p[v][k] , inf ) , u = g[u][k] , v = g[v][k];
        F.Add( i , p[u][0] , inf ) , F.Add( i , p[v][0] , inf );
    }
    vector<int> s , t;
    pii E[MAXN];
    int main() {
        cin >> n >> m;
        F.init( 3000000 );
        for( int i = 1 , u , v ; i < n ; ++ i ) {
            scanf("%d%d",&u,&v);
            G[u].push_back( v ) , G[v].push_back( u );
            E[i] = mp( u , v );
        }
        dep[1] = 1 , dfs( 1 , 1 );
        for( int i = 1 ; i < n ; ++ i )
            if( g[E[i].fi][0] == E[i].se ) tt[i] = T[E[i].fi];
            else tt[i] = T[E[i].se];
        for( int i = 1 , u , v ; i <= m ; ++ i ) {
            scanf("%d%d",&u,&v);
            S[i] = F.Add( 1 , ++ cn , 1 );
            link( cn , u , v );
        }
        cout << F.maxflow( 1 , 2 ) << endl;
        for( int i = 1 ; i <= m ; ++ i ) bacs[S[i]] = i;
        for( int i = 1 ; i < n ; ++ i ) bact[tt[i]] = i;
        F.work( 1 );
        for( int i = F.head[1] ; i ; i = F.nxt[i] ) if( !F.vis[F.to[i]] )
            s.push_back( bacs[i ^ 1] );
    //    F.work( 2 );
        for( int i = F.head[2] ; i ; i = F.nxt[i] ) if( F.vis[2] ^ F.vis[F.to[i]] )
            t.push_back( bact[i] );
        cout << s.size() << ' '; for( auto i : s ) printf("%d ",i); puts("");
        cout << t.size() << ' '; for( auto i : t ) printf("%d ",i); puts("");
    }
    
  • 相关阅读:
    CocoaPods 的简单快速安装方法
    macOS Catalina new Shell,解决 The default interactive shell is now zsh
    Mac入门--通过homebrew下载过慢问题
    Mac下安装Android Studio
    Mac更新catalina之后有道词典闪退的解决办法
    mac系统下安装Java开发环境(一)——JDK安装
    聊天案例
    ios中常用k线
    ubuntu连接蓝牙鼠标
    image_transport
  • 原文地址:https://www.cnblogs.com/yijan/p/cf786e.html
Copyright © 2011-2022 走看看