【NOI2015】小园丁和老司机

题面

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

题解

$orz$ $aysn$

神仙题不会,还是$aysn$教我的。

二合一。

第一问是个$dp$,我一开始想建$DAG$跑最长路,后来经题解点化可以把同一层的一起考虑,这样就能做到$O(n)$了。

方法:

$f[x]$:假设新到了$x$(这一层的其他点都没有访问),允许向同一层的其他点转移,点$x$向后的最长路。
$g[x]$:要离开$x$,不允许向同一层的其他点转移,点$x$向后的最长路。

然后$O(n^2)->O(n)$(单调队列都不用,直接记录前缀后缀$max$就行了)

第二问是上下界网络流

$S$向每个点连$INF$边,每个点向$T$连$INF$边,在保留“可能留下非左右方向车辙印”的边,下界为1。

发现边只有下界没有上界,把第一次调整略去,直接让有盈余的点流向$T$,$S$流向缺流入的点(直观理解),在代码上直接建流过后的反边就可以了。

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100050
#define INF 1000000007
#define ri register int
using namespace std;

int f[N],g[N];
int nxtf[N],nxtg[N];
int n,x[N],y[N],id[N];
int r1[N],c1[N],r2[N],c2[N],r3[N],c3[N],r4[N],c4[N];
vector<int> ph1[N],ph2[N],ph3[N],ph4[N];
bool vis[N];

bool cmp1(int a,int b) {
  return y[a]<y[b] || (y[a]==y[b]&&x[a]<x[b]);
}
bool cmp2(int a,int b) {
  return x[a]+y[a]<x[b]+y[b] || (x[a]+y[a]==x[b]+y[b]&&y[a]<y[b]);
}
bool cmp3(int a,int b) {
  return x[a]-y[a]<x[b]-y[b] || (x[a]-y[a]==x[b]-y[b]&&y[a]<y[b]);
}
bool cmp4(int a,int b) {
  return x[a]<x[b] || (x[a]==x[b]&&y[a]<y[b]);
}

int dp(int x);

int predp(int x) {
  if (g[x]!=-1) return g[x];
  int r,c,ans=0;
  r=r2[x],c=c2[x];
  if (c+1<ph2[r].size() && dp(ph2[r][c+1])+1>ans) {
    ans=f[ph2[r][c+1]]+1;
    nxtg[x]=ph2[r][c+1];
  }
  r=r3[x],c=c3[x];
  if (c+1<ph3[r].size() && dp(ph3[r][c+1])+1>ans) {
    ans=f[ph3[r][c+1]]+1;
    nxtg[x]=ph3[r][c+1];
  }
  r=r4[x],c=c4[x];
  if (c+1<ph4[r].size() && dp(ph4[r][c+1])+1>ans) {
    ans=f[ph4[r][c+1]]+1;
    nxtg[x]=ph4[r][c+1];
  }
  g[x]=ans;
  return ans;
}

int dp(int x) {
  if (f[x]!=-1) return f[x];
  int r=r1[x],n=ph1[r].size(),curm,curp;
  for (ri i=0;i<n;i++) {
    f[ph1[r][i]]=predp(ph1[r][i]);
    nxtf[ph1[r][i]]=ph1[r][i];
  }
  curm=-1000000007;curp=-1;
  for (ri i=0;i<n;i++) {
    if (curm+n-1>f[ph1[r][i]]) f[ph1[r][i]]=curm+n-1,nxtf[ph1[r][i]]=curp;
    if (g[ph1[r][i]]-i>curm) curm=g[ph1[r][i]]-i,curp=ph1[r][i];
  }
  curm=-1000000007; curp=-1;
  for (ri i=n-1;i>=0;i--) {
    if (curm>f[ph1[r][i]]) f[ph1[r][i]]=curm,nxtf[ph1[r][i]]=curp;
    if (g[ph1[r][i]]+i>curm) curm=g[ph1[r][i]]+i,curp=ph1[r][i];
  }
  return f[x];
}

void print(int x,bool s) {
  if (s==0) {
    int y=nxtf[x];
    int r=r1[y],c=c1[y];
    if (c1[x]<c) {
      for (ri i=c1[x]-1;i>=0;i--) printf("%d ",ph1[r][i]);
      for (ri i=c1[x]+1;i<=c;i++) printf("%d ",ph1[r][i]);
    }
    else if (c1[x]>c) {
      for (ri i=c1[x]+1;i<ph1[r].size();i++) printf("%d ",ph1[r][i]);
      for (ri i=c1[x]-1;i>=c;i--) printf("%d ",ph1[r][i]);
    }
    print(y,1);
  }
  else if (s==1) {
    int y=nxtg[x];
    if (!y) return;
    printf("%d ",y);
    print(y,0);
  }
}

int dis(int x,int y) {
  if (c1[x]<c1[y]) return c1[y];
  return ph1[r1[x]].size()-c1[y]-1;
}

struct graph {
  vector<int> ed[N],w,to;
  int d[N],cur[N],p[N];
  #define S (n+1)
  #define T 0
  void add_edge(int u,int v,int tw) {
    to.push_back(v); w.push_back(INF); ed[u].push_back(to.size()-1);
    to.push_back(u); w.push_back(0);   ed[v].push_back(to.size()-1);
  }
  void add_edges(int u,int v,int tw){
    to.push_back(v); w.push_back(tw);  ed[u].push_back(to.size()-1);
    to.push_back(u); w.push_back(INF); ed[v].push_back(to.size()-1);
  }
  bool bfs() {
    queue<int> q;
    memset(d,0x3f,sizeof(d));
    d[S]=0; q.push(S);
    while (!q.empty()) {
      int x=q.front(); q.pop();
      for (ri i=0;i<ed[x].size();i++) {
        int e=ed[x][i];
        if (d[x]+1<d[to[e]] && w[e]) {
          d[to[e]]=d[x]+1;
          q.push(to[e]);
        }
      }
    }
    return d[T]<INF;
  }
  int dfs(int x,int limit) {
    if (x==T || limit==0) return limit;
    int sum=0; 
    for (ri &i=cur[x];i<ed[x].size();i++) {
      int e=ed[x][i];
      if (w[e] && d[x]+1==d[to[e]]) {
        int f=dfs(to[e],min(limit,w[e]));
        if (!f) continue;
        sum+=f; limit-=f; 
        w[e]-=f; w[1^e]+=f;
        if (!limit) return sum;
      }
    }
    return sum;
  }
  int dinic() {
    int ret=0;
    while (bfs()) {
      memset(cur,0,sizeof(cur));
      ret+=dfs(S,INF);
    }
    return ret;
  }
  int work() {
    for (ri i=0;i<to.size();i+=2) {
      p[to[1^i]]--;
      p[to[i]]++;
    }
    int flow=0;
    for (ri i=1;i<=n;i++) {
      if (p[i]>0) {
        add_edges(n+1,i,p[i]);
        flow+=p[i];
      }
      else if (p[i]<0) {
        add_edges(i,0,-p[i]);
      }
    }
    flow-=dinic();
    return flow;
  }
} G;

void redp(int x,int s) {
  if (vis[x+s*n]) return;
  vis[x+s*n]=1;
  if (s==0) {
    if (f[x]==g[x]) redp(x,1);
    int n=ph1[r1[x]].size();
    for (ri i=0;i<n;i++) if (i!=c1[x]) {
      if (f[x]-g[ph1[r1[x]][i]]==dis(x,ph1[r1[x]][i])) redp(ph1[r1[x]][i],1);
    }
  }
  else {
    int r,c,ans=0;
    r=r2[x],c=c2[x];
    if (c+1<ph2[r].size() && g[x]==f[ph2[r][c+1]]+1) {
      G.add_edge(x,ph2[r][c+1],INF);
      redp(ph2[r][c+1],0);
    }
    r=r3[x],c=c3[x];
    if (c+1<ph3[r].size() && g[x]==f[ph3[r][c+1]]+1) {
      G.add_edge(x,ph3[r][c+1],INF);
      redp(ph3[r][c+1],0);
    }
    r=r4[x],c=c4[x];
    if (c+1<ph4[r].size() && g[x]==f[ph4[r][c+1]]+1) {
      G.add_edge(x,ph4[r][c+1],INF);
      redp(ph4[r][c+1],0);
    }
  }
}

int main() {
  int cc;
  scanf("%d",&n);
  for (ri i=1;i<=n;i++) scanf("%d %d",&x[i],&y[i]);
  for (ri i=1;i<=n;i++) id[i]=i;

  ri i,j;
  sort(id,id+n+1,cmp1);
  cc=0;
  for (i=0;i<=n;i+=j) {
    ++cc;
    for (j=0;y[id[i+j]]==y[id[i]]&&i+j<=n;j++) {
      ph1[cc].push_back(id[i+j]);
      r1[id[i+j]]=cc;
      c1[id[i+j]]=j;
    }
  }
  
  sort(id,id+n+1,cmp2);
  cc=0;
  for (i=0;i<=n;i+=j) {
    ++cc;
    for (j=0;x[id[i+j]]+y[id[i+j]]==x[id[i]]+y[id[i]]&&i+j<=n;j++) {
      ph2[cc].push_back(id[i+j]);
      r2[id[i+j]]=cc;
      c2[id[i+j]]=j;
    }
  }
  
  sort(id,id+n+1,cmp3);
  cc=0;
  for (i=0;i<=n;i+=j) {
    ++cc;
    for (j=0;x[id[i+j]]-y[id[i+j]]==x[id[i]]-y[id[i]]&&i+j<=n;j++) {
      ph3[cc].push_back(id[i+j]);
      r3[id[i+j]]=cc;
      c3[id[i+j]]=j;
    }
  }
  
  sort(id,id+n+1,cmp4);
  cc=0;
  for (i=0;i<=n;i+=j) {
    ++cc;
    for (j=0;x[id[i+j]]==x[id[i]]&&i+j<=n;j++) {
      ph4[cc].push_back(id[i+j]);
      r4[id[i+j]]=cc;
      c4[id[i+j]]=j;
    }
  }
  memset(f,-1,sizeof(f));
  memset(g,-1,sizeof(g));
  printf("%d\n",dp(0));
  print(0,0); puts("");
  redp(0,0);
  printf("%d\n",G.work()); 
  return 0;
}

 

posted @ 2019-08-01 21:59  HellPix  阅读(179)  评论(0编辑  收藏  举报