zoukankan      html  css  js  c++  java
  • CF343E Pumping Stations

    (n) 个点 (m) 条边的带权无向图。

    你需要构造一个排列,收益为 (sum_{i=2}^n mathrm{mincut}(a_{i-1},a_i))

    (mathrm{mincut}(S,T)) 表示图中 (S) 为源点,(T) 为汇点的最小割。

    求最大的收益,并输出方案。

    $2le nle 200 $ , $ 1le mle 1000$


    对无向图建出来最小割树,现在问题转化为了定义树上两点路径权值是路径上的边权最小值,构造一个排列,使得相邻两点的路径权值和最大。

    我们考虑对当前的一棵树,取出边权最小的一条边,那么我们一定要只经过这条边一次,于是去掉这条边就变成了两个子问题,分治下去就可以构造出来了。

    构造答案这部分实现的好是可以做到 (O(nlog nalpha(n))) 的,而且我写的也是这种。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 200;
    const int inf = 1e9;
    using namespace std;
    struct edges
    {
    	int u,v,w;
    }edge[N + 5];
    int n,m,t[N + 5],t1[N + 5],t2[N + 5],e1[N + 5],e2[N + 5],e[N + 5],edge_cnt,fa[N + 5],a[N + 5],ans;
    namespace F
    {
        const int N = 3e6;
        const long long inf = 2e18;
        struct edges
        {
            int to;
            long long cost;
        }edge[N * 2 + 5],e[N * 2 + 5];
        int nxt[N * 2 + 5],head[N + 5],edge_cnt = 1,dis[N + 5],q[N + 5],cur[N + 5],S,T;
        void add_edge(int u,int v,long long w)
        {
            edge[++edge_cnt] = (edges){v,w};
            nxt[edge_cnt] = head[u];
            head[u] = edge_cnt;
        }
        void add(int u,int v,long long w)
        {
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        int bfs()
        {
            for (int i = 1;i <= n;i++)
                cur[i] = head[i],dis[i] = 0;
            int l = 1,r = 0;
            dis[S] = 1;
            q[++r] = S;
            while (l <= r)
            {
                int u = q[l++];
                for (int i = head[u];i;i = nxt[i])
                {
                    int v = edge[i].to,w = edge[i].cost;
                    if (w && !dis[v])
                    {
                        dis[v] = dis[u] + 1;
                        q[++r] = v;
                    }
                }
            }
            return dis[T];
        }
        long long dfs(int u,long long flow)
        {
            if (u == T)
                return flow;
            long long sm = 0;
            for (int &i = cur[u];i;i = nxt[i])
            {
                int v = edge[i].to;
                long long w = edge[i].cost;
                if (dis[v] == dis[u] + 1 && w)
                {
                    long long res = dfs(v,min(w,flow));
                    edge[i].cost -= res;
                    edge[i ^ 1].cost += res;
                    sm += res;
                    flow -= res;
                    if (!flow)
                        break;
                }
            }
            return sm;
        }
        void init()
        {
        	for (int i = 2;i <= edge_cnt;i++)
        		e[i] = edge[i];
        }
        void clear()
        {
            for (int i = 2;i <= edge_cnt;i++)
            	edge[i] = e[i];
        }
        long long dinic(int s,int t)
        {
            S = s;T = t;
            clear();
            long long ans = 0;
            while (bfs())
                ans += dfs(S,inf);
            return ans;
        }
    }
    int find(int x)
    {
    	if (fa[x] == x)
    		return x;
    	return fa[x] = find(fa[x]);
    }
    void build(int l,int r)
    {
    	if (l >= r)
    		return;
    	int val = F::dinic(t[l],t[r]),cnt1 = 0,cnt2 = 0;
    	edge[++edge_cnt] = (edges){t[l],t[r],val};
    	for (int i = l;i <= r;i++)
    		if (F::dis[t[i]])
    			t1[++cnt1] = t[i];
    		else
    			t2[++cnt2] = t[i];
    	for (int i = 1;i <= cnt1;i++)
    		t[i] = t1[i];
    	for (int i = 1;i <= cnt2;i++)
    		t[i + cnt1] = t2[i];
    	build(1,cnt1);
    	build(cnt1 + 1,cnt2 + cnt1);
    }
    void solve(int l,int r,int ql,int qr)
    {
    	if (l > r)
    		return;
    	if (l == r)
    	{
    		a[l] = t[l];
    		return;
    	}
    	for (int i = l;i <= r;i++)
    		fa[t[i]] = t[i];
    	int mi = inf,id = 0,cnt1 = 0,cnt2 = 0,q1 = 0,q2 = 0;
    	for (int i = ql;i <= qr;i++)
    		if (edge[e[i]].w < mi)
    			mi = edge[e[i]].w,id = e[i];
    	ans += mi;
    	for (int i = ql;i <= qr;i++)
    		if (e[i] != id)
    			fa[find(edge[e[i]].u)] = find(edge[e[i]].v);
    	int x = find(edge[id].u);
    	for (int i = l;i <= r;i++)
    	{
    		if (find(t[i]) == x)
    			t1[++cnt1] = t[i];
    		else
    			t2[++cnt2] = t[i];
    	}
    	for (int i = ql;i <= qr;i++)
    		if (e[i] != id)
    		{
    			if (find(edge[e[i]].u) == x)
    				e1[++q1] = e[i];
    			else
    				e2[++q2] = e[i];
    		}
    	for (int i = 1;i <= cnt1;i++)
    		t[i + l - 1] = t1[i];
    	for (int i = 1;i <= cnt2;i++)
    		t[l + i + cnt1 - 1] = t2[i];
    	for (int i = 1;i <= q1;i++)
    		e[i + ql - 1] = e1[i];
    	for (int i = 1;i <= q2;i++)
    		e[i + q1 + ql - 1] = e2[i];
    	solve(l,l + cnt1 - 1,ql,ql + q1 - 1);
    	solve(l + cnt1,r,ql + q1,ql + q1 + q2 - 1);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int u,v,w;
    	for (int i = 1;i <= m;i++)
    	{
    		scanf("%d%d%d",&u,&v,&w);
    		F::add(u,v,w);
    	}
    	F::init();
    	for (int i = 1;i <= n;i++)
    		t[i] = i;
    	build(1,n);
    	for (int i = 1;i <= n;i++)
    		t[i] = i;
    	for (int i = 1;i < n;i++)
    		e[i] = i;
    	solve(1,n,1,n - 1);
    	cout<<ans<<endl;
    	for (int i = 1;i <= n;i++)
    		printf("%d ",a[i]);
    	return 0;
    }
    
  • 相关阅读:
    找到数组或整数列表中连续子序列的最大和
    编写一个调用的函数,该函数接受一个括号字符串,并确定括号的顺序是否有效
    SRS流媒体服务器搭建及拉取摄像头视频流经opencv处理后再推流至SRS
    (pymysql.err.OperationalError) (1055, "Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column
    微信商户转帐到个人零钱
    双色球1千万,等你来拿!
    python后端开发面试总结
    alipay接入步骤
    Mongodb简单操作
    flask基础
  • 原文地址:https://www.cnblogs.com/sdlang/p/14593363.html
Copyright © 2011-2022 走看看