LOJ#3097. 「SNOI2019」通信 最小费用流+主席树优化建图
如果做过软件开发,餐巾计划问题的话这题就秒切了.
还是类似的套路:借流思想.
正解的话就是无聊地上一个主席树优化建图就行.
维护一颗边权为正数地主席树,再维护一颗边权为负数的主席树就行.
主席树写了,感觉好恶心......
code:
#include <bits/stdc++.h> #define N 3008 #define inf 1000000000 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int s,t,n,m,flow; ll ans; namespace mcmf { int a[N],flow2[N],inq[N]; ll d[N]; struct Edge { int u,v,cap,cost; Edge(int u=0,int v=0,int cap=0,int cost=0):u(u),v(v),cap(cap),cost(cost){} }; queue<int>q; vector<int>G[N]; vector<Edge>edges; inline void add(int u,int v,int cap,int cost) { edges.push_back(Edge(u,v,cap,cost)); edges.push_back(Edge(v,u,0,-cost)); int p=edges.size(); G[u].push_back(p-2); G[v].push_back(p-1); } int spfa() { for(int i=0;i<N;++i) d[i]=flow2[i]=inf; memset(inq,0,sizeof(inq)); d[s]=0,inq[s]=1,q.push(s); while(!q.empty()) { int u=q.front(); q.pop(),inq[u]=0; for(int i=0;i<G[u].size();++i) { Edge e=edges[G[u][i]]; if(e.cap>0&&d[e.v]>d[u]+e.cost) { d[e.v]=d[u]+e.cost; flow2[e.v]=min(flow2[u],e.cap); a[e.v]=G[u][i]; if(!inq[e.v]) { inq[e.v]=1; q.push(e.v); } } } } if(d[t]==inf) return 0; int f=flow2[t]; flow+=f; int u=edges[a[t]].u; edges[a[t]].cap-=f; edges[a[t]^1].cap+=f; while(u!=s) { edges[a[u]].cap-=f; edges[a[u]^1].cap+=f; u=edges[a[u]].u; } ans+=(ll)d[t]*f; return 1; } inline int maxflow() { while(spfa()); return flow; } inline ll getcost() { return ans; } }; int I1(int x) { return x; } int I2(int x) { return x+n; } int val[N]; int main() { // setIO("input"); int W; scanf("%d%d",&n,&W); for(int i=1;i<=n;++i) scanf("%d",&val[i]); s=0,t=(n<<1)+1; for(int i=1;i<=n;++i) { mcmf::add(s,I1(i),1,0); mcmf::add(I2(i),t,1,0); mcmf::add(s,I2(i),1,W); } for(int i=1;i<=n;++i) { for(int j=i+1;j<=n;++j) { int det=abs(val[i]-val[j]); mcmf::add(I1(i),I2(j),1,det); // 直接借光 } } mcmf::maxflow(); printf("%lld\n",mcmf::getcost()); return 0; }