UOJ#132&bzoj4200[Noi2015]小园丁与老司机
Part A
把坐标离散化,按照纵坐标为第一关键字,横坐标为第二关键字排序
以$f_i$记录来到$i$这个点最多经过点数,那么答案显而易见就是$f_i$加上该层点数
转移的话就是分三种来到这个点的方案
对于每一种考虑:
1)直接上来
2)通过左边某个点上来,把左边所有点都走完
3)通过右边某个点上来,把右边所有点都走完
然后对于每一层维护从左边来的最大值和从右边来的最大值即可
Part B
从任意一个满足答案的结束点往开始点沿任意有效路径走即可
Part C
很显然,找到所有有可能经过的边做最小路径覆盖就是答案了
同样很显然要去维护每个点所有有可能的前置点也是不可能的..
那么就去用一种比较奥妙重重的方法
比如说对于你已经知道了$u->v$这一条边是要走的,那么对于$u$来说:
1)如果$f_u+1=f_v$,直接标记$u$
2)如果从左(右)边某个点走上来的,那么标记$u$点前(后)一个表示该点前(后)的最大值都应被标记
等到去扫那一层的时候再去标记那些点
这样即可做到$O(n)$的时间复杂度
对于最小路径覆盖,可以用普通网络流和上下界最小流..
但是普通网络流貌似要大一点..
因为这个上下界最小流保证可行,所以并不需要再加$ed->st$的边来求
直接把总流量和现流量一减就行了..
Code
花了两天怒敲6k+..
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;
const int Maxn = 50010;
const int inf = 0x7fffffff;
int s[3][Maxn];
int b[3][Maxn], bl[3];
int bb[Maxn], bbl;
int begin[Maxn], end[Maxn], sy[Maxn];
int f[Maxn], Maxl[Maxn], Maxlnum[Maxn], Maxr[Maxn], Maxrnum[Maxn];
int pre[3][Maxn];
int lj[Maxn], ljl;
bool vl[Maxn], vr[Maxn], v[Maxn];
struct enode {
int y, next, c, opp;
}a[Maxn*18]; int first[Maxn], len;
int st, ed, sst, eed, d[Maxn];
int h[Maxn];
void ins(int x, int y, int c) {
len++; int k1 = len;
a[len].y = y; a[len].c = c;
a[len].next = first[x]; first[x] = len;
len++; int k2 = len;
a[len].y = x; a[len].c = 0;
a[len].next = first[y]; first[y] = len;
a[k1].opp = k2;
a[k2].opp = k1;
}
int _max(int x, int y) { return x > y ? x : y; }
int _min(int x, int y) { return x < y ? x : y; }
bool bfs() {
queue <int> q;
memset(h, -1, sizeof(h));
h[sst] = 0;
q.push(sst);
while(!q.empty()){
int x = q.front(); q.pop();
for(int k = first[x]; k; k = a[k].next){
int y = a[k].y;
if(h[y] == -1 && a[k].c > 0){
h[y] = h[x]+1;
q.push(y);
}
}
}
return h[eed] > 0;
}
int dfs(int x, int flow) {
if(x == eed) return flow;
int delta = 0;
for(int k = first[x]; k; k = a[k].next){
int y = a[k].y;
if(h[y] == h[x]+1 && a[k].c > 0 && flow-delta > 0){
int minf = dfs(y, _min(a[k].c, flow-delta));
delta += minf;
a[k].c -= minf;
a[a[k].opp].c += minf;
}
}
if(delta == 0) h[x] = -1;
return delta;
}
struct node {
int x, y, num, p[3];
}list[Maxn];
bool cmp(node x, node y) {
if(x.y != y.y) return x.y < y.y;
return x.x < y.x;
}
int n;
int main() {
int i, j, k;
scanf("%d", &n);
for(i = 1; i <= n; i++){
scanf("%d%d", &list[i].x, &list[i].y);
list[i].num = i;
b[0][i] = list[i].p[0] = list[i].x-list[i].y;
b[1][i] = list[i].p[1] = list[i].x;
b[2][i] = list[i].p[2] = list[i].x+list[i].y;
bb[i] = list[i].y;
}
n++;
sort(list+1, list+n+1, cmp);
for(i = 0; i < 3; i++){
sort(b[i]+1, b[i]+n+1);
bl[i] = unique(b[i]+1, b[i]+n+1) - (b[i]+1);
}
sort(bb+1, bb+n+1);
bbl = unique(bb+1, bb+n+1) - (bb+1);
int l = 1;
sy[1] = 1;
for(i = 2; i <= n; i++){
if(list[i].y != list[i-1].y) l++;
sy[i] = l;
}
j = 1;
for(i = 1; i <= bbl; i++){
begin[i] = j;
while(list[j].y == bb[i] && j <= n) j++;
end[i] = j-1;
}
//Part A
for(i = 2; i <= n; i++) f[i] = -1;
int p0;
for(i = 0; i < 3; i++){
p0 = lower_bound(b[i]+1, b[i]+bl[i]+1, 0) - b[i];
s[i][p0] = 1;
}
Maxl[1] = -1; Maxlnum[1] = 1; Maxr[1] = 1; Maxrnum[1] = 1;
for(i = 2; i <= bbl; i++){
int p, o, u, v;
for(j = begin[i]; j <= end[i]; j++){
for(k = 0; k < 3; k++){
p = lower_bound(b[k]+1, b[k]+bl[k]+1, list[j].p[k]) - b[k];
if(s[k][p] > 0){
u = s[k][p]; pre[k][j] = u;
o = sy[u];
if(f[u] != -1) f[j] = _max(f[j], f[u]+1);
if(u != begin[o] && Maxlnum[u-1] > 0) f[j] = _max(f[j], Maxl[u-1]+u-begin[o]+1);
if(u != end[o] && Maxrnum[u+1] > 0) f[j] = _max(f[j], Maxr[u+1]+end[o]-u+1);
}
s[k][p] = j;
}
}
if(f[begin[i]] > 0){
Maxl[begin[i]] = f[begin[i]];
Maxlnum[begin[i]] = begin[i];
}
for(j = begin[i]+1; j <= end[i]; j++){
Maxl[j] = Maxl[j-1]; Maxlnum[j] = Maxlnum[j-1];
if((f[j] >= Maxl[j] || Maxlnum[j] == 0) && f[j] > 0){
Maxl[j] = f[j];
Maxlnum[j] = j;
}
}
if(f[end[i]] > 0){
Maxr[end[i]] = f[end[i]];
Maxrnum[end[i]] = end[i];
}
for(j = end[i]-1; j >= begin[i]; j--){
Maxr[j] = Maxr[j+1]; Maxrnum[j] = Maxrnum[j+1];
if((f[j] >= Maxr[j] || Maxrnum[j] == 0) && f[j] > 0){
Maxr[j] = f[j];
Maxrnum[j] = j;
}
}
}
int ans = 0, now = 1;
for(i = 2; i <= n; i++){
if(f[i]+end[sy[i]]-begin[sy[i]] > ans){
ans = f[i]+end[sy[i]]-begin[sy[i]];
now = i;
}
}
printf("%d\n", ans);
//Part B
ljl = 0;
for(i = end[sy[now]]; i > now; i--) lj[++ljl] = list[i].num;
for(i = begin[sy[now]]; i < now; i++) lj[++ljl] = list[i].num;
while(now != 1){
lj[++ljl] = list[now].num;
int u;
for(k = 0; k < 3; k++){
u = pre[k][now];
if(u > 0){
if(f[u]+1 == f[now]){ now = u; break; }
if(u != begin[sy[u]] && Maxl[u-1]+u-begin[sy[u]]+1 == f[now] && Maxlnum[u-1] > 0){
for(i = u; i > Maxlnum[u-1]; i--) lj[++ljl] = list[i].num;
for(i = begin[sy[u]]; i < Maxlnum[u-1]; i++) lj[++ljl] = list[i].num;
now = Maxlnum[u-1];
break;
}
if(u != end[sy[u]] && Maxr[u+1]+end[sy[u]]-u+1 == f[now] && Maxrnum[u+1] > 0){
for(i = u; i < Maxrnum[u+1]; i++) lj[++ljl] = list[i].num;
for(i = end[sy[u]]; i > Maxrnum[u+1]; i--) lj[++ljl] = list[i].num;
now = Maxrnum[u+1];
break;
}
}
}
}
for(i = ljl; i > 1; i--) printf("%d ", lj[i]);
if(ljl >= 1) printf("%d", lj[1]);
printf("\n");
//Part C
for(i = 2; i <= n; i++){
if(f[i]+end[sy[i]]-begin[sy[i]] == ans) v[i] = true;
}
st = n+1; ed = st+1; sst = ed+1; eed = sst+1;
for(i = bbl; i >= 1; i--){
int bjm, u;
bjm = n+1;
for(j = end[i]; j >= begin[i]; j--){
if(vl[j] == true) bjm = Maxl[j];
if(f[j] == bjm) v[j] = true;
}
bjm = n+1;
for(j = begin[i]; j <= end[i]; j++){
if(vr[j] == true) bjm = Maxr[j];
if(f[j] == bjm) v[j] = true;
}
for(j = begin[i]; j <= end[i]; j++){
if(v[j] == false) continue;
for(k = 0; k < 3; k++){
u = pre[k][j];
if(u == 0) continue;
bool bk = false;
if(f[u]+1 == f[j]) v[u] = true, bk = true;
if(u != begin[sy[u]] && Maxl[u-1]+u-begin[sy[u]]+1 == f[j] && Maxlnum[u-1] > 0){
vl[u-1] = true;
bk = true;
}
if(u != end[sy[u]] && Maxr[u+1]+end[sy[u]]-u+1 == f[j] && Maxrnum[u+1] > 0){
vr[u+1] = true;
bk = true;
}
if(bk == true){
d[j]++; d[u]--;
ins(u, j, inf-1);
}
}
}
}
int sum = 0;
for(i = 1; i <= n; i++){
ins(st, i, inf);
ins(i, ed, inf);
if(d[i] > 0) ins(sst, i, d[i]), sum += d[i];
else ins(i, eed, -d[i]);
}
int delta = 0;
while(bfs()) delta += dfs(sst, inf);
printf("%d\n", sum-delta);
/*ins(ed, st, inf);
while(bfs()) delta += dfs(sst, inf);
printf("%d\n", a[len].c);*/
return 0;
}
最后说点什么..
这道题是真的搞了很久
在不停的考虑细节、修改、压缩..
看到这个也是满满的感动..
作者:Ra1nbow
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。