[ZJOI2011] 最小割 - 最小割树

最小割树裸题

建树后,以每个点为根跑DFS求出距离矩阵,然后暴力回答询问即可

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int maxn=6e2;
const int maxm=4e4;
const int inf=1e13;

int n,m,q;

//for the target graph
vector <pair<int,int> > g[maxn];

void clear1() {
    for(int i=1;i<=n;i++) g[i].clear();
}

inline void add(int u,int v,int c) {
    g[u].push_back(make_pair(v,c));
}

int cnt,p[maxn],tmp[maxn],S[maxn];

//cnt stands for the first few Uni-blocks
//p[i] represents the number of the point on the i-th point
//tmp array is used to copy the sort p array
//S[u] indicates the Unicom block number where u is in

void clear2() {
    cnt=0;
    memset(p,0,sizeof p);
    memset(tmp,0,sizeof tmp);
    memset(S,0,sizeof S);
}

struct GHT {
    int s,t,maxFlow,cur[maxn];

    int edgeNum=-1,head[maxn],to[maxm<<1],nxt[maxm<<1];
    int w[maxm<<1],f[maxm<<1];

    GHT() {memset(head,-1,sizeof(head));}

    inline void add_edge(int u,int v,int c) {
        nxt[++edgeNum]=head[u];head[u]=edgeNum;
        to[edgeNum]=v;w[edgeNum]=c;
    }

    int dep[maxn],gap[maxn];

    inline void bfs() {
        memset(dep,0,sizeof(dep));memset(gap,0,sizeof(gap));
        dep[t]=gap[1]=1;queue<int> Q;Q.push(t);
        while(!Q.empty()) { int u=Q.front();Q.pop();
            for(int i=head[u];i!=-1;i=nxt[i]) if(!dep[to[i]])
                ++gap[dep[to[i]]=dep[u]+1],Q.push(to[i]);
        }
    }

    int dfs(int u,int lastFlow) {
        int used=0,minFlow=0;
        if(u==t) {maxFlow+=lastFlow;return lastFlow;}
        for(int &i=cur[u];i!=-1;i=nxt[i])
            if(f[i]&&dep[to[i]]+1==dep[u])
                if(minFlow=dfs(to[i],min(lastFlow-used,f[i])))
                {   f[i]-=minFlow;f[i^1]+=minFlow;
                    if((used+=minFlow)==lastFlow) return used;
                }
        if(!(--gap[dep[u]++])) dep[s]=n+1;
        ++gap[dep[u]];return used;
    }

    inline int ISAP(int x,int y) {
        for(register int i=0;i<=edgeNum;++i) f[i]=w[i];
        maxFlow=0;s=x;t=y;bfs();while(dep[s]<=n) {
            for(register int i=0;i<=n;++i) cur[i]=head[i];
            dfs(s,inf);
        }return maxFlow;
    }

    void dfs(int u) { S[u]=cnt;
        for(int i=head[u];i!=-1;i=nxt[i])
            if(f[i]&&S[to[i]]!=cnt) dfs(to[i]);
    }

    void build(int l,int r) {
        if(l>=r) return ;
        int x=p[l],y=p[l+1],cut=ISAP(x,y),L=l,R=r;
        ++cnt;dfs(x);add(x,y,cut);add(y,x,cut);
        for(register int i=l;i<=r;++i) tmp[S[p[i]]==cnt?L++:R--]=p[i];
        for(register int i=l;i<=r;++i) p[i]=tmp[i];
        build(l,L-1);build(R+1,r);
    }
};

int vis[maxn],f[maxn],ans[maxn][maxn];

void clear3() {
    memset(vis,0,sizeof vis);
    memset(f,0,sizeof f);
    memset(ans,0,sizeof ans);
}

void dfs(int p) {
    vis[p]=1;
    for(int i=0;i<g[p].size();i++) {
        if(vis[g[p][i].first]) continue;
        f[g[p][i].first]=min(f[p],g[p][i].second);
        dfs(g[p][i].first);
    }
}

signed main() {
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--) {
        GHT tree;
        cin>>n>>m;
        for(int i=1;i<=n;i++) p[i]=i; //remember this
        for(int i=1;i<=m;i++) {
            int t1,t2,t3;
            cin>>t1>>t2>>t3;
            tree.add_edge(t1,t2,t3);
            tree.add_edge(t2,t1,t3);
        }
        tree.build(1,n);
        for(int i=1;i<=n;i++) {
            memset(vis,0,sizeof vis);
            f[i]=inf;
            dfs(i);
            for(int j=1;j<=n;j++) {
                if(vis[j]) ans[i][j]=f[j];
                else ans[i][j]=0;
            }
        }
        cin>>q;
        for(int i=1;i<=q;i++) {
            int lim;
            cin>>lim;
            int tot=0;
            for(int j=1;j<=n;j++) {
                for(int k=1;k<j;k++) {
                    if(ans[j][k]<=lim) ++tot;
                }
            }
            cout<<tot<<endl;
        }
        cout<<endl;
        clear1();
        clear2();
        clear3();
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/12272802.html

时间: 2024-08-26 16:10:04

[ZJOI2011] 最小割 - 最小割树的相关文章

bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)

2229: [Zjoi2011]最小割 题目:传送门 题解: 一道非常好的题目啊!!! 蒟蒻的想法:暴力枚举点对跑最小割记录...绝对爆炸啊.... 开始怀疑是不是题目骗人...难道根本不用网络流???一看路牌....分治最小割?最小割树? 然后开始各种%论文... 简单来说吧,根据各种本蒟蒻不会证明的理论,那么:所有最小割都不是完全独立的,总共有n-1种(也就是树上的n-1条边)最小割 恰好和树的定义一样啊! 那么用一个solve递归函数来解决,一开始任意找两个点作为st和ed来最小割,然后分

scu - 3254 - Rain and Fgj(最小点权割)

题意:N个点.M条边(2 <= N <= 1000 , 0 <= M <= 10^5),每一个点有个权值W(0 <= W <= 10^5),现要去除一些点(不能去掉点0),使得结点 0 与结点 N - 1 不连通,求去掉的点的最小权值和. 题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=3254 -->>这是很明显的最小点权割.. 建图方案: 1)将全部点 i 拆成 i 和 i + N.i ->

3532: [Sdoi2014]Lis 最小字典序最小割

3532: [Sdoi2014]Lis Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 865  Solved: 311[Submit][Status][Discuss] Description 给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci.请删除若干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案.如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种. 这题难点在如何求一组最小字典序最小的最小

关于最小代价子母树

第一次尝试写动态规划(Dynamic Planning)= 问题如下: ------------------------------------------------------------------------------------------------------------------------- 最小代价子母树 设有一排数,共n个,例如:22 14 7 13 26 15 11.任意2个相邻的数可以进行归并,归并的代价为该两个数的和,经过不断的归并,最后归为一堆,而全部归并代价的

poj 3522 Slim Span 最大边减最小边最小的生成树

枚举最小边进行kruskal. #include <cstdio> #include <algorithm> using namespace std; #define maxn 120 #define maxm 10000 struct edge { int u,v,w; }e[maxm]; int p[maxn],n,m; int find(int x) { if(x==p[x]) return x; return p[x]=find(p[x]); } void link(int

【BZOJ-2229】最小割 最小割树(最大流+分治)

2229: [Zjoi2011]最小割 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1565  Solved: 560[Submit][Status][Discuss] Description 小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割. 对于带权图来说,将所有顶点处在不同部分的边的

BZOJ 2229 ZJOI2011 最小割 最小割+分治 400AC达成&amp;&amp;2000Submission达成

题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值 最小割分治- - 首先朴素的想法是做O(n^2)遍网络流 但是这样显然是过不去的 根据一些结论,最小割最多有n-1个,这n-1个最小割构成一个最小割树 别问我为什么- - 因此我们分治寻找这n-1个最小割 每层分治,先任选两个点作为源汇做一遍最小割 然后找出S集和T集,对所有S集的点和T集的点构成的点对用本次得到的最小割更新一遍 注意更新的是全部S集和全部T集,不只是本次分治内部的S集和T集 然后将本次分治的点分成S集和T集,

【BZOJ-4519】不同的最小割 最小割树(分治+最小割)

4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 393  Solved: 239[Submit][Status][Discuss] Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将 所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t

【BZOJ4519】[Cqoi2016]不同的最小割 最小割树

[BZOJ4519][Cqoi2016]不同的最小割 Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割.而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了.我们可以把视野放宽,考虑有N个点的无向连通图中所有点对的最