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;
}

  


最后说点什么..

这道题是真的搞了很久

在不停的考虑细节、修改、压缩..

看到这个也是满满的感动..

posted @ 2017-02-21 18:55  Ra1nbow  阅读(458)  评论(0编辑  收藏  举报