网络优化

网络优化

https://ac.nowcoder.com/acm/problem/20951

分析

我们看出,这是一个匹配问题。左边的点只能匹配右边的节点。而一个节点可以匹配的数量为 。我们可以考虑用网络流来解决这个问题。

  • 向左边节点 连接一条容量为 边。

  • 右边节点 连接一条容量为 的边。

  • 如果右侧节点 满足 ,那么左侧节点 连一条容量为 的边。最后

但是我们发现这样连边时间复杂度为 的,要考虑优化。因为连的边是一个连续的区间,我们其实可以考虑线段树优化建边。那么总边数为 。 那么用 的总复杂度为 。由于网络流好像基本跑不满,所以也就过了。

代码

#include<bits/stdc++.h>
using namespace std;
int read() {
    int x = 0,f = 0;char ch = getchar();
    while(!isdigit(ch)) {if(ch=='-')f=1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return f?-x:x;
}
const int N = 4e6 + 10,inf = 0x3f3f3f3f;
struct Line{int l,r,v;}line[N];
struct Edge{int to,nxt,cap;}e[N];
int n,m,dis[N],head[N],cur[N],ecnt;
queue<int> Q;
void add(int x,int y,int cap) {
    e[++ecnt].to = y;e[ecnt].cap = cap;e[ecnt].nxt = head[x];head[x] = ecnt;
    e[++ecnt].to = x;e[ecnt].cap = 0;  e[ecnt].nxt = head[y];head[y] = ecnt;
}
void update(int u,int l,int r,int id) {
    if(line[id].l <= l && r <= line[id].r) {add(id + 4 * n,u,inf);return;}
    if(l > line[id].r || r < line[id].l) return;
    int mid = l + r >> 1;
    update(u<<1,l,mid,id);update(u<<1|1,mid+1,r,id);
}
void build(int u,int l,int r) {
    if(l == r) {add(u,4 * n + m + 1,1);return;}
    int mid = l + r >> 1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);
    add(u,u<<1,inf);add(u,u<<1|1,inf);
}
bool bfs(int s,int t) {
    while(!Q.empty()) Q.pop();memset(dis,0,sizeof(dis));dis[s] = 1;
    Q.push(s);while(!Q.empty()) {
        int x = Q.front();Q.pop();for(int i = head[x];i;i = e[i].nxt) {
            if(!dis[e[i].to] && e[i].cap > 0) {
                dis[e[i].to] = dis[x] + 1;Q.push(e[i].to);
                if(e[i].to == t) return true;
            }
        }
    }
    return false;
}
int dfs(int x,int a,int t) {
    if(t == x || a == 0) return a;
    int flow = 0,f;for(int i = cur[x];i;i = e[i].nxt) {
        cur[x] = i;int y = e[i].to;
        if((dis[y] == dis[x] + 1) && ((f=dfs(y,min(a,e[i].cap),t))>0)) {
            e[i].cap -= f;e[i^1].cap += f;flow += f;a -= f;if(!a) break;
        }
    }
    return flow;
}
int main() {
    while(scanf("%d%d",&n,&m) != -1) {
        ecnt = 1;memset(head,0,sizeof(head));
        for(int i = 1;i <= m;i++) {
            scanf("%d%d%d",&line[i].l,&line[i].r,&line[i].v);update(1,1,n,i);
        }
        build(1,1,n);
        int S = 0,T = 4 * n + m + 1,maxflow = 0;
        for(int i = 1;i <= m;i++) add(S,4 * n + i,line[i].v);
        while(bfs(S,T)) {
            for(int i = 0;i <= T;i++) cur[i] = head[i];
            maxflow += dfs(S,inf,T);
        }
        printf("%d\n",maxflow);
    }

    return 0;
}
全部评论
人有多大胆,地有多大产
点赞 回复 分享
发布于 2020-10-01 21:37

相关推荐

小红书 后端选手 n*16*1.18+签字费期权
点赞 评论 收藏
分享
点赞 评论 收藏
分享
微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
5 1 评论
分享
牛客网
牛客企业服务