题面
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; }
原文:https://www.cnblogs.com/shxnb666/p/11285659.html