LOJ3097 SNOI2019 通信 题解

题目链接

费用流,当建边需要依靠位置和权值两个偏序关系时,可以用cdq分治优化建边。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 20007
  4 #define M 200007
  5 const int inf=0x3f3f3f3f;
  6 #define ll long long
  7 struct flow
  8 {
  9     int hd[N],pre[M],to[M],num,w[M],mf[N],fa[N],maf,s,t;
 10     ll f[M],dis[N],ans;
 11     bool vis[N];
 12     queue<int> q;
 13     void adde(int x,int y,int z,int l)
 14         {
 15             num++;pre[num]=hd[x];hd[x]=num;to[num]=y;w[num]=z;f[num]=l;
 16             num++;pre[num]=hd[y];hd[y]=num;to[num]=x;w[num]=0;f[num]=-l;
 17         }
 18     void Init()
 19         {
 20             num=1;
 21         }
 22     bool spfa()
 23         {
 24             memset(dis,0x3f,sizeof(dis));
 25             memset(vis,0,sizeof(vis));
 26             while(!q.empty())q.pop();
 27             int i,v,u;
 28             dis[s]=0;
 29             mf[s]=inf;
 30             q.push(s);
 31             while(!q.empty())
 32             {
 33                 v=q.front();q.pop();
 34                 vis[v]=false;
 35                 for(i=hd[v];i;i=pre[i])
 36                 {
 37                     u=to[i];
 38                     if(w[i]&&dis[v]+f[i]<dis[u])
 39                     {
 40                         dis[u]=dis[v]+f[i];
 41                         fa[u]=i;
 42                         mf[u]=min(mf[v],w[i]);
 43                         if(!vis[u])
 44                         {
 45                             vis[u]=true;
 46                             q.push(u);
 47                         }
 48                     }
 49                 }
 50             }
 51             return dis[t]<1e18;
 52         }
 53     void update()
 54         {
 55             int v=t,i,fl=mf[t];
 56             while(v!=s)
 57             {
 58                 i=fa[v];
 59                 w[i]-=fl;
 60                 w[i^1]+=fl;
 61                 v=to[i^1];
 62             }
 63             ans+=dis[t]*fl;
 64             maf+=fl;
 65         }
 66     void main()
 67         {
 68             while(spfa())
 69                 update();
 70         }
 71 }D;
 72 struct str
 73 {
 74     int a,p;
 75 }p[N],tmp[N];
 76 bool operator <(str a,str b)
 77 {
 78     return a.p<b.p;
 79 }
 80 int tot,Pre[N],Suf[N],n;
 81 void cdq(int l,int r)
 82 {
 83     if(l==r)return;
 84     int mid=l+r>>1,i;
 85     cdq(l,mid),cdq(mid+1,r);
 86     for(i=l;i<mid;i++)
 87     {
 88         ++tot;
 89         Pre[i]=tot;
 90         D.adde(tot,p[i].p+n,inf,0);
 91         D.adde(tot+1,tot,inf,p[i+1].a-p[i].a);
 92     }
 93     ++tot;
 94     Pre[mid]=tot;
 95     D.adde(tot,p[mid].p+n,inf,0);
 96     for(i=mid;i>l;i--)
 97     {
 98         ++tot;
 99         Suf[i]=tot;
100         D.adde(tot,p[i].p+n,inf,0);
101         D.adde(tot+1,tot,inf,p[i].a-p[i-1].a);
102     }
103     ++tot;
104     Suf[l]=tot;
105     D.adde(tot,p[l].p+n,inf,0);
106     int j=l-1;
107     for(i=mid+1;i<=r;i++)
108     {
109         while(j<mid&&p[j+1].a<p[i].a)j++;
110         if(j>=l)D.adde(p[i].p,Pre[j],inf,p[i].a-p[j].a);
111         if(j<mid)D.adde(p[i].p,Suf[j+1],inf,p[j+1].a-p[i].a);
112     }
113     i=l,j=mid+1;
114     int k=l;
115     while(i<=mid&&j<=r)
116     {
117         if(p[i].a<p[j].a)
118             tmp[k++]=p[i++];
119         else tmp[k++]=p[j++];
120     }
121     while(i<=mid)tmp[k++]=p[i++];
122     while(j<=r)tmp[k++]=p[j++];
123     for(i=l;i<=r;i++)
124         p[i]=tmp[i];
125 }
126 int main()
127 {
128     int i,x,y,w;
129     scanf("%d%d",&n,&w);
130     for(i=1;i<=n;i++)
131     {
132         scanf("%d",&x);
133         p[i]={x,i};
134     }
135     D.Init();
136     D.s=2*n+1,D.t=2*n+2;
137     tot=2*n+2;
138     for(i=1;i<=n;i++)
139     {
140         D.adde(D.s,i,1,0);
141         D.adde(i,D.t,1,w);
142         D.adde(i+n,D.t,1,0);
143     }
144     sort(p+1,p+n+1);
145     cdq(1,n);
146     D.main();
147     printf("%lld
",D.ans);
148     return 0;
149 }
原文地址:https://www.cnblogs.com/lishuyu2003/p/11160726.html