Educational Codeforces Round 34 G. Yet Another Maxflow Problem 線段樹實現最小割

題目鏈接: https://codeforces.com/contest/903/problem/G

題意:

在理解網絡流的前提下簡化的題目大概是,源點向 A1A_{1} 連流量 infinf , BnB_n 向匯點連流量 infinf,對於每個 i[1,n1]i\in[1,n-1] 都有一條 AiAi+1A_i\rightarrow A_{i+1} 以及 BiBi+1B_i\rightarrow B_{i+1} 的邊,流量均已知,同時告訴你 mmAxByA_x\rightarrow B_y 的流量已知的邊。 現在要進行 qq 次操作,每次操作改變一條 AxAx+1A_x\rightarrow A_{x+1} 的邊的流量,每次改變後問你當前的最大流。

做法:

表示 27002700 的題目不愧是 27002700的題目,別說自己想了…連看人家的題解都看了半天才明白… (在自閉的邊緣徘徊)

自己表述可能不太好,就藉着大佬的博客內容稍微說一說。

最小割爲什麼被稱之爲最小割,因爲:

AA 側的點中,若割掉了 (AxAx+1)(A_x→A_{x+1}),那麼所有的邊 (AyAy+1)(y>x)(A_y→A_{y+1})(y>x) 失去意義。
BB 側的點中,若割掉了 (BxBx+1)(B_x→B_{x+1}),那麼所有的邊 (ByBy+1)(y<x)(B_y→B_{y+1})(y<x) 失去意義

我們知道的是,在 AA 側和 BB 側中一定有一遍是滿足上述條件的,只要一側滿足,那麼另一側一定能找到一個剛好符合的點。

我們假設 (AxAx+1)(A_x→A_{x+1})(BxBx+1)(B_x→B_{x+1}) 是符合我們要的兩條邊,那麼 (AuBv)(ux,y<v)(A_u→B_v)(u≤x,y<v) 都是需要被割掉的邊集。

我們從 AA 側的點 11 開始往 nn 枚舉,不斷令該點之前的流量變爲 infinf 來嘗試,如果是從這個往後因爲滿流而斷掉所需要的最大流量。

線段樹裏存放是的點 BB 的合法流量,點 jj 一點代表的是 B[j1]+u=1iv=jncap(AuBv)B[j-1]+\sum_{u=1}^{i}\sum_{v=j}^{n}cap(A_u\rightarrow B_v) ,表示我們在確定了 AA 側的 iiBB 側的 jj 之後需要割的流量。 我們每次都取 BB 側的最小值即可。

我一開始的時候對這個做法很是疑惑,但是模了之後也慢慢理解了。。覺得很是神奇的一道題目。

代碼

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r)/2
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int maxn=200005;
ll mx[maxn<<2],laz[maxn<<2];
ll n,m,q,A[maxn],B[maxn],flow[maxn];
vector<pll> ve[maxn];
void build(int l,int r,int rt){
    if(l==r) {
        mx[rt]=(ll)B[l-1];
        return ;
    }
    build(l,mid,lson);
    build(mid+1,r,rson);
    mx[rt]=min(mx[lson],mx[rson]);
}
void deal(int rt,ll v){
    mx[rt]+=v,laz[rt]+=v;
}
void push_down(int rt){
    if(laz[rt]){
        deal(lson,laz[rt]);
        deal(rson,laz[rt]);
        laz[rt]=0ll;
    }
}
void update(int l,int r,int rt,int ql,int qr,ll v){
    if(ql<=l&&r<=qr){
        deal(rt,v);
        return ;
    }
    push_down(rt);
    if(ql<=mid) update(l,mid,lson,ql,qr,v);
    if(qr>mid) update(mid+1,r,rson,ql,qr,v);
    mx[rt]=min(mx[lson],mx[rson]);
}
multiset<ll> S;
int main(){
    scanf("%lld%lld%lld",&n,&m,&q);
    rep(i,1,n-1) scanf("%lld%lld",&A[i],&B[i]);
    rep(i,1,m){
        ll x,y,c; scanf("%lld%lld%lld",&x,&y,&c);
        ve[x].push_back({y,c});
    }
    build(1,n,1);
    //printf("%d\n",ve[1].size());
    rep(i,1,n){
        for(auto p:ve[i]){
            update(1,n,1,1,p.first,p.second);
        }
        flow[i]=mx[1];
        S.insert(A[i]+flow[i]);
    }
    printf("%lld\n",*(S.begin()));
    rep(k,1,q){
        int x,y;scanf("%d%d",&x,&y);
        S.erase(S.find(A[x]+flow[x]));
        A[x]=y; S.insert(A[x]+flow[x]);
        printf("%lld\n",*(S.begin()));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章