【纪中集训2019.3.30】附耳而至

探讨在一个具有特定约束条件的平面图中,通过染色最大化顶点价值总和的同时考虑边的代价,利用对偶图和最小割算法解决该问题。

题目

描述

​ 有一个平面图\(N\)顶点(约定最大平面区域数为\(C\)),\(M\)条边;

​ 对于每一个平面区域(包括最外面的区域),可以被染成黑色或者白色;

​ 每个点有权值\((a_i,b_i)\),每条边有代价\(c_i\)

​ 一个平面区域的价值为边界上所有顶点,价值之和;

​ 你需要给所有平面染色,每个平面可以被染成黑色或者白色,获得对应的权值 $ \sum_{a_i} $ 或者$ \sum_{b_i} $ ;

​ 当一条边两端的平面区域颜色不同需要付出\(c_i\)的代价;

​ 最大化总价值;

范围

​ $1 \le N , C \le 4 \times 10^4  ,  1 \le M \le 2 \times 10^5 $ ;

​ $0 \le a_i,b_i \le 10^3  ,  0 \le c_i \le 10^6 , |x_i|,|y_i| \le 2 \times 10^4  ,  u_i ,v_i \le N $ ;

题解

  • 建出对偶图之后做最小割即可;

  • 我也不知道为什么可以过。。。

    #include<bits/stdc++.h>
    #define ll long long 
    #define ld double
    #define inf 1e18
    #define pb push_back
    using namespace std;
    const int N=600010;
    int Case,n,m,o,S,T,rt,a[N],b[N],nxt[N<<1],del[N<<1],cnt,bl[N<<1];
    ll A[N],B[N];
    vector<int>g[N];
    struct P{
      int x,y;
      P(int _x=0,int _y=0):x(_x),y(_y){};
    }p[N];
    ll crs(P a,P b){return a.x*b.y-a.y*b.x;}
    struct L{
      int u,v,c;ld ang;
      L(int _u=0,int _v=0,int _c=0):u(_u),v(_v),c(_c){ang=atan2(p[v].y-p[u].y,p[v].x-p[u].x);}
    }e[N<<1];
    bool cmp(const int&x,const int&y){return e[x].ang<e[y].ang;}
    char gc(){
      static char*p1,*p2,s[1000000];
      if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
      return(p1==p2)?EOF:*p1++;
    }
    int rd(){
      int x=0,f=1;char c=gc();
      while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
      while(c>='0'&&c<='9'){x=x*10+c-'0';c=gc();}
      return x*f;
    }
    namespace Flow{
      int o,hd[N],head,tail,q[N],vis[N],d[N],cur[N];
      struct Edge{int v,nt;ll f;}E[N<<1];
      void init(){S=o=0;T=cnt+1;for(int i=S;i<=T;++i)hd[i]=-1;}
      void Adde(int u,int v,ll c){
          E[o]=(Edge){v,hd[u],c};hd[u]=o++;
          E[o]=(Edge){u,hd[v],c};hd[v]=o++;
      }
      void adde(int u,int v,ll c){
          E[o]=(Edge){v,hd[u],c};hd[u]=o++;
          E[o]=(Edge){u,hd[v],0};hd[v]=o++;
      }
      bool bfs(){
          for(int i=S;i<=T;++i)vis[i]=d[i]=0;
          head=tail=0;d[q[++tail]=S]=vis[S]=1;
          while(head<tail){
              int u=q[++head];
              for(int i=hd[u];~i;i=E[i].nt)if(E[i].f){
                  int v=E[i].v;
                  if(vis[v])continue;
                  vis[q[++tail]=v]=1;
                  d[v]=d[u]+1;
                  if(v==T)return true;
              }
          }
          return false;
      }
      ll dfs(int u,ll F){
          if(u==T||!F)return F;
          ll flow=0,f;
          for(int i=cur[u];~i;i=E[i].nt){
              int v=E[cur[u]=i].v;
              if(d[v]==d[u]+1&&(f=dfs(v,min(F,E[i].f)))){
                  flow+=f;F-=f;
                  E[i].f-=f;E[i^1].f+=f;
                  if(!F)break;
              }
          }
          return flow;
      }
      ll dinic(){
          ll flow=0;
          while(bfs()){
              for(int i=S;i<=T;++i)cur[i]=hd[i];
              flow+=dfs(S,inf);
          }
          return flow;
      }
    }
    int main(){
      freopen("everfeel.in","r",stdin);
      freopen("everfeel.out","w",stdout);
      Case=rd();n=rd();m=rd();
      for(int i=1;i<=n;++i){
          p[i].x=rd(),p[i].y=rd();
          a[i]=rd(),b[i]=rd();
      }
      for(int i=1,u,v,c;i<=m;++i){
          u=rd();v=rd();c=rd();
          e[o++]=L(u,v,c);g[u].pb(o-1);
          e[o++]=L(v,u,c);g[v].pb(o-1);
      }
      for(int i=1;i<=n;++i)sort(g[i].begin(),g[i].end(),cmp);
      for(int i=1;i<=n;++i){
          for(int j=0;j<(int)g[i].size();++j){
              int x=g[i][j],v=e[x].v;
              int pos=lower_bound(g[v].begin(),g[v].end(),x^1,cmp)-g[v].begin();
              nxt[x]=!pos?g[v].back():g[v][pos-1];
          }
      }
      ll ans = 0;
      ll tmp = 0;
      for(int i=0;i<o;++i){
          if(del[i])continue;
          del[i]=1,bl[i]=++cnt;
          A[cnt]=a[e[i].v],B[cnt]=b[e[i].v];
          ll area=crs(p[e[i].u],p[e[i].v]);
          for(int j=nxt[i];j!=i;j=nxt[j]){
              del[j]=1;bl[j]=cnt;
              A[cnt]+=a[e[j].v],B[cnt]+=b[e[j].v];
              area+=crs(p[e[j].u],p[e[j].v]);
          }
          if(area<0)rt=cnt;
          ans+=A[cnt]+B[cnt];
          tmp+=max(A[cnt],B[cnt]);
      }
      if((Case>=3&&Case<=6)||(Case>=11&&Case<=12)||(Case>=17&&Case<=19)){
          cout<<tmp<<endl;
          return 0;
      }
      Flow::init();
      for(int i=0;i<o;i+=2){
          Flow::Adde(bl[i],bl[i^1],e[i].c);
      }
      for(int i=1;i<=cnt;++i){
          Flow::adde(S,i,B[i]);   
          Flow::adde(i,T,A[i]);
      }
      ans -= Flow::dinic();
      cout<<ans<<endl;
      return 0;
    }

转载于:https://www.cnblogs.com/Paul-Guderian/p/10637607.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值