zoukankan      html  css  js  c++  java
  • CF903G Yet Another Maxflow Problem 解题报告 (线段树)

    CF903G Yet Another Maxflow Problem

    题意

    (A,B) 两列点, 每列都有 (n) 个点 ((n le 2 imes 10^5)).

    对于任意 (i in [1,n-1]), (a_i)(a_{i+1}), (b_i)(b_{i+1}) 之间都有一条给定权值的连边,

    (A)(B) 之间有 (m) 条给定权值的边 ((m le 2 imes 10^5)).

    (q) 个操作 (( q le 2 imes 10^5)),

    每次操作要求修改一条 (a_i)(a_{i+1}) 之间的边, 并询问修改后 (a_1)(b_n) 的最大流.


    思路

    首先, 最大流等于最小割.


    假设我们选定了 (i,j), 要割掉 ((a_i,a_{i+1}))((b_j,b_{j+1})) 这两条边,

    那么 (A,B) 之间要割的边就是左端点小于等于 (i), 右端点大于等于 (j+1) 的边,

    (E={(x,y)| x le i, y ge j+1}).


    修改操作只会修改 (A) 之间的边, 所以我们可以预处理出 选定了 (A) 中的割边后所需要的最小代价.

    我们可以从小到大枚举 (i), 表示选择要割掉 ((a_i,a_{i+1})).

    设当前枚举到 (k), 这时, 我们在 (B) 中选取某些点的代价就要加上 (A,B) 之间左端点小于等于 (k) 的边的代价.


    对于一条边 ((x,y)), 其中 (x le k),

    若要割掉 (B) 中的 ((b_j,b_{j+1})) 这条边, 且 (j le y), 则就要加上 (w(x,y)) 的代价.

    所以, 我们可以用线段树来维护当前选取 (B) 中的点的最小代价.


    处理好了 选定了 (A) 中的 (每条) 割边后所需要的最小代价 后, 我们可以把这些最小代价加上 (A) 中对应边的权值, 再把它们扔进线段树里,

    这时, 线段树的最小值就代表从 (a_1)(b_n) 的最小割.

    然后每次修改 (A) 中边的权值时, 在线段树上单点修改就行了, 询问就区间查询最小值.


    代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int _=2e5+7;
    const int __=8e5+7;
    const ll inf=1e17;
    int n,m,q;
    ll wgt[2][_],cst[_],minx[__],tag[__];   // 0: A  1: B
    struct edge{
      int x,y;
      ll w;
    }e[_];
    void build(int k,int l,int r,bool id){
      tag[k]=0;
      if(l==r){
        if(!id){
          minx[k]=wgt[0][l]+cst[l];
        }
        else minx[k]=wgt[1][l];
        return;
      }
      int mid=(l+r)>>1;
      build(k<<1,l,mid,id);
      build(k<<1|1,mid+1,r,id);
      minx[k]=min(minx[k<<1],minx[k<<1|1]);
    }
    bool rule_x(edge a,edge b){ return a.x<b.x; }
    void init(){
      cin>>n>>m>>q; n--;
      for(int i=1;i<=n;i++)
        scanf("%lld%lld",&wgt[0][i],&wgt[1][i]);
      for(int i=1;i<=m;i++)
        scanf("%d%d%lld",&e[i].x,&e[i].y,&e[i].w);
      sort(e+1,e+1+m,rule_x);
      build(1,0,n,1);
    }
    void upd(int k,ll w){
      minx[k]+=w;
      tag[k]+=w;
    }
    void psd(int k){
      if(!tag[k]) return;
      upd(k<<1,tag[k]);
      upd(k<<1|1,tag[k]);
      tag[k]=0;
    }
    void modify(int k,int l,int r,int x,int y,ll w){
      if(l>=x&&r<=y){ upd(k,w); return; }
      psd(k);
      int mid=(l+r)>>1;
      if(x<=mid) modify(k<<1,l,mid,x,y,w);
      if(y>mid) modify(k<<1|1,mid+1,r,x,y,w);
      minx[k]=min(minx[k<<1],minx[k<<1|1]);
    }
    ll query(int k,int l,int r,int x,int y){
      if(l>=x&&r<=y) return minx[k];
      psd(k);
      int mid=(l+r)>>1;
      ll t1=inf,t2=inf;
      if(x<=mid) t1=query(k<<1,l,mid,x,y);
      if(y>mid) t2=query(k<<1|1,mid+1,r,x,y);
      return min(t1,t2);
    }
    void pre(){
      int p=1;
      for(int i=1;i<=n+1;i++){
        while(p<=m&&e[p].x<=i){
          modify(1,0,n,0,e[p].y-1,e[p].w);
          p++;
        }
        if(i==n+1) cst[0]=query(1,0,n,0,n);
        else cst[i]=query(1,0,n,0,n);
      }
      build(1,0,n,0);
    }
    void run(){
      printf("%lld
    ",query(1,0,n,0,n));
      int x; ll w;
      for(int i=1;i<=q;i++){
        scanf("%d%lld",&x,&w);
        modify(1,0,n,x,x,-wgt[0][x]+w);
        wgt[0][x]=w;
        printf("%lld
    ",query(1,0,n,0,n));
      }
    }
    int main(){
    #ifndef ONLINE_JUDGE
      freopen("x.in","r",stdin);
    #endif
      init();
      pre();
      run();
      return 0;
    }
    
  • 相关阅读:
    go语言之goroute协程
    Vue中Computed和Watch的用法及区别
    php判断复选框是否被选中的方法
    基于workerman的实时推送
    织梦引入公共模板
    织梦快速建站首页模板
    golang解决中文乱码的方法
    Vue项目中使用可视化图表echarts
    解决for循环中异步请求顺序不一致的问题
    layui多图上传实现删除功能的方法
  • 原文地址:https://www.cnblogs.com/BruceW/p/12192877.html
Copyright © 2011-2022 走看看