【SNOI2019】通信

题面

https://www.luogu.org/problem/P5331

题解

莫名的感觉像餐巾计划问题。

一开始和餐巾错的一样(两次在一个坑里面跌倒了。。。。)后来安装餐巾的思路改一改就对了。

$orz yyb$

$orz zsy$

分治连边。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#define N 65000
#define ri register int
#define LL long long
#define S 0
#define T (2*n+1)
#define INF 1000000007
using namespace std;

int n,w,cc;
int id[N],t[N],a[N];

struct graph {
  vector<int> to,w,len,ed[N];
  int vis[N],cur[N],dis[N];
  void add_edge(int u,int v,int tw,int tl) {
    w.push_back(tw); len.push_back(tl); to.push_back(v); ed[u].push_back(w.size()-1);
    w.push_back(0); len.push_back(-tl); to.push_back(u); ed[v].push_back(w.size()-1);
  }
  bool spfa() {
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    queue<int> q;
    dis[S]=0; q.push(S); vis[S]=1;
    while (!q.empty()) {
      int x=q.front(); q.pop();
      for (ri i=0;i<ed[x].size();i++) {
        int e=ed[x][i];
        if (w[e] && dis[to[e]]>dis[x]+len[e]) {
          dis[to[e]]=dis[x]+len[e];
          if (!vis[to[e]]) {
            vis[to[e]]=1;
            q.push(to[e]);
          }
        }
      }
      vis[x]=0;
    }
    return dis[T]<INF;
  }
  int dfs(int x,int limit) {
    if (x==T || !limit) return limit;
    vis[x]=1; int sum=0;
    for (ri &i=cur[x];i<ed[x].size();i++) {
      int e=ed[x][i];
      if (w[e] && dis[to[e]]==dis[x]+len[e] && !vis[to[e]]) {
        int f=dfs(to[e],min(limit,w[e]));
        if (!f) continue;
        w[e]-=f; w[1^e]+=f;
        sum+=f; limit-=f;
        if (!limit) return sum;
      }
    }
    return sum;
  }
  int zkw() {
    int ret=0;
    while (spfa()) {
      memset(vis,0,sizeof(vis));
      memset(cur,0,sizeof(cur));
      ret+=dfs(S,INF)*dis[T];
    }
    return ret;
  }
} G;

bool cmp(int x,int y) {return a[x]<a[y];}

void link(int l,int r) {
  if (l==r) return;
  for (ri i=l;i<=r;i++) id[i]=i;
  sort(id+l,id+r+1,cmp);
  for (ri i=l;i<=r;i++) t[i]=++cc;
  for (ri i=l;i<r;i++) {
    G.add_edge(t[i],t[i+1],INF,a[id[i+1]]-a[id[i]]);
    G.add_edge(t[i+1],t[i],INF,a[id[i+1]]-a[id[i]]);
  }
  int mid=(l+r)/2;
  for (ri i=l;i<=r;i++)
    if (id[i]<=mid) G.add_edge(id[i]+n,t[i],1,0); else G.add_edge(t[i],id[i],1,0);
  link(l,mid); link(mid+1,r);
}

int main(){
  scanf("%d %d",&n,&w);
  for (ri i=1;i<=n;i++) scanf("%d",&a[i]);
  for (ri i=1;i<=n;i++) G.add_edge(S,i,1,w);
  for (ri i=1;i<=n;i++) G.add_edge(i,T,1,0);
  for (ri i=1;i<=n;i++) G.add_edge(S,i+n,1,0);
  cc=T; link(1,n);
  cout<<G.zkw()<<endl;
}
原文地址:https://www.cnblogs.com/shxnb666/p/11277867.html