[bzoj3218] a+b problem [最小割+数据结构优化建图]

题面

传送门

思路

最小割

我们首先忽略掉那个奇♂怪的限制,就有一个比较显然的最小割模型:

建立源点$S$和汇点$T$

对于每个元素$i$建立一个点$i$,连边$<S,i,w[i]>$和$<i,T,b[i]>$

这样,割掉$<S,i>$边就表示选白色,割掉$<i,T>$边就表示选黑色,那么答案就是$\sum_{i=1}^nb[i]+w[i] - mincut$

但是现在有一个奇♂怪的限制出来了

奇♂怪的限制

这个限制,是当$i$点黑色,$j<i$点白色时出现的

那么我们考虑把这个限制对答案的影响,也用最小割的方式表现出来

我们发现,如果对于某一个点$i$,它对应的割边(就是在上面那种方法里面)是$<i,T>$,也就是它取白色的话,这个限制不会被触发

那么我们就考虑这个点的割边是$<S,i>$的情况,此时我们发现,如果我们想把这个$p[i]$也变成最小割的一部分的话,我们就要对于所有可能触发的$j$,构成一条这样的链:

$<S,i>-<i,j>-<j,T>$

但是这个中间这条,显然不能直接在$i,j$中间连边,因为这样无法体现出链的特性

我们考虑这样的一个方法,来分开黑白割的情况

我们对于每个点,新建节点$ii$,然后对于每个$ii$,连边$<ii,i,p[i]>$

对于$i$所有能够访问到的点,连边$<i,jj,inf>$,$inf$表示不可割

这样跑最小割,还是用所有的$b,w$的和来减,就是答案了

建图优化

显然这个东西直接连边的话,$n^2$的会炸

所以我们用一个主席树来优化一下建图

用所有的$i$连向对应的主席树链上的所有点,主席树上的点就横向连边(旧的往新的连),然后每个点从它覆盖的所有区间连过来

开的主席树的数组下标意义就是$a$的大小,这样方便取区间

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<cmath>
#define ll long long
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
int n,first[200010],cnte=-1,dep[200010],cur[200010];
struct edge{
    int to,next;ll w;
}a[1500010];
void add(int u,int v,ll w){
    a[++cnte]=(edge){v,first[u],w};first[u]=cnte;
    a[++cnte]=(edge){u,first[v],0};first[v]=cnte;
}
bool bfs(int s,int t){
    int i,u,v,q[200010],head=0,tail=1;
    for(i=s;i<=t;i++) dep[i]=-1,cur[i]=first[i];
    dep[s]=0;q[0]=s;
    while(head<tail){
        u=q[head++];
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;if(~dep[v]||!a[i].w) continue;
            dep[v]=dep[u]+1;q[tail++]=v;
        }
    }
    return ~dep[t];
}
int dfs(int u,int t,ll lim){
    if(u==t||!lim) return lim;
    int i,v,f,flow=0;
    for(i=cur[u];~i;i=a[i].next){
        v=a[i].to;cur[u]=i;
        if(dep[v]==dep[u]+1&&(f=dfs(v,t,min(a[i].w,lim)))){
            flow+=f;lim-=f;
            a[i].w-=f;a[i^1].w+=f;
            if(!lim) return flow;
        }
    }
    if(lim) dep[u]=-1;
    return flow;
}
ll dinic(int s,int t){
    ll re=0;
    while(bfs(s,t)) re+=dfs(s,t,1e12);
    return re;
}
struct chairmantree{
    int ch[1000010][2],cnt,root[5010];
    int insert(int l,int r,int pos,int pre,int u){
        int cur=++cnt;
        ch[cur][0]=ch[pre][0];ch[cur][1]=ch[pre][1];
        add(u,cur,1e12);
        if(l==r){
            if(pre) add(pre,cur,1e12);
            return cur;
        }
        int mid=(l+r)>>1;
        if(mid>=pos){
            ch[cur][0]=insert(l,mid,pos,ch[pre][0],u);
            if(pre) add(pre,cur,1e12);
        }
        else{
            ch[cur][1]=insert(mid+1,r,pos,ch[pre][1],u);
            if(pre) add(pre,cur,1e12);
        }
        return cur;
    }
    void check(int l,int r,int ql,int qr,int cur,int u){
        if(!cur) return;
        int mid=(l+r)>>1;
        if(l>=ql&&r<=qr){
            add(cur,u,1e12);
            return;
        }
        if(mid>=ql) check(l,mid,ql,qr,ch[cur][0],u);
        if(mid<qr) check(mid+1,r,ql,qr,ch[cur][1],u);
    }
}T;
int main(){
    memset(first,-1,sizeof(first));
    n=read();int i,val,b,w,l,r,p;ll sum=0;
    int s=0,t=200000;T.cnt=n<<1;
    for(i=1;i<=n;i++){
        val=read();b=read();w=read();l=read();r=read();p=read();
        sum+=(ll)b+w;
        add(s,i,w);add(i,t,b);add(i+n,i,p);
        T.root[i]=T.insert(0,1e9,val,T.root[i-1],i);
        T.check(0,1e9,l,r,T.root[i-1],i+n);
    }
    printf("%lld\n",sum-dinic(s,t));
}

原文地址:https://www.cnblogs.com/dedicatus545/p/9451944.html

时间: 2024-10-16 01:26:27

[bzoj3218] a+b problem [最小割+数据结构优化建图]的相关文章

cf786E ALT (最小割+倍增优化建图)

如果把“我全都要”看作是我全不要的话,就可以用最小割解决啦 源点S,汇点T 我们试图让每个市民作为一个等待被割断的路径 把狗狗给市民:建边(S,i,1),其中i是市民 把狗狗给守卫:建边(j,T,1),其中j是守卫(也就是边) 市民要在路上所有边看到狗:建边(i,j,1),其中i是市民,j是i经过的边 (众所周知,(!A)&(!B)==!(A|B),所以要把两种选择串起来) 然而这样边数太多了,考虑倍增来优化建边 ...反正就是倍增优化建边,流量给正无穷 最大流=最小割,跑个dinic就行了(要

数据结构优化建图总结

数据结构优化建图总结 线段树优化建图 把要连的区间拆成log个点(线段树上的点)连要要连的点上,如果是区间连区间可以建\(\log^2\) 条边 注意,区间连进去和连出来的边顺序不一样,线段树建法也不同 单点连区间(连进去) 由于本质是链接所有根节点,线段树父亲向儿子连零边,保证能到达 区间连单点(连出去)由于所有根节点连这个点,线段树儿子向父亲连零边,能够连出去 此时就需要两颗线段树 例题:CF786B 我会告诉你们用大根堆维护dijkstra还过了前四个点 改longlong看线段树看了半天

BZOJ 3218 A+B Problem(最大流 + 主席树优化建图)

题目:A+B Problem 感谢 Nietzsche 在省选紧迫之际花 39' 给我讲这道题. 这题我并没有想出来,感觉又浪费一道好题了. 需要用最小割,建模方式如下(假设若 2 取黑色,1 取白色会使 2 为奇怪方格): 跑一边最大流,求出最小割,用所有的 W + 所有的 B - 最小割,就是答案. 不过,对于每一个结点 2,在寻找像 1 这样(li <= aj <= ri)的结点时,总不能一个一个枚举吧? O(n2) T 飞. 所以,需要用主席树优化一下.线段树优化建图笔记. 代码未完待

一个神秘的oj2587 你猜是不是dp(线段树优化建图)

哇 这难道不是happiness的翻版题嘛? 从\(S\)向一个点连染成白色的收益 从这个点向\(T\)连染成黑色的收益 对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T,连流量为收益 这不就结束了吗? 自信写完,提交 woc!!只有40分? #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath>

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙

/** 题目:poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙 链接:http://poj.org/problem?id=3680 题意:给定n个区间,每个区间(ai,bi),以及权值wi.选出一些区间,满足权值和最大且任何一个点不会被超过k个区间覆盖. 思路: 建图:对于每个区间(ai,bi). ai->bi,cap = 1,cost = -wi; (离散化后的ai,bi) 所有区间的端点放到数组,进行从小到大排序,去重,离散化,在数组内相邻的u端点,v端点.u->

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)

[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖走型 八连通型 本质上只有两种类型(走一大串/走八连通),我们考虑这样一种建图方法: 对于每一行每一列建立一个点(点权为\(0\)) 对于关键点建立一个点(点权为\(1\)) 然后考虑这样一种建图方式,得到一个有点权无边权图 关键点所在的行与列无偿地向这个关键点连边 横走型的关键点向行连一条边,竖走