一开始你在原点,有n棵许愿树,你每次可以向左,右,左上,右上,上到达最近的一棵许愿树许愿。问最多能到达多少许愿树,输出方案。在所有可能的路径中,保留所有非左右的边,问最小路径覆盖所有的边。n <= 50000, y坐标相同的点不超过1000
首先按y坐标排序,使用map进行转移,同层的点一起转移。
建出第三问的图后,考虑一个点的入度和出度,如果路径不可相交,答案就是Σmax(in[x] - out[x], 0),考虑增建平行边,就可以网络流了。
/**************************************************************
Problem: 4200
User: hzt1
Language: C++
Result: Accepted
Time:2696 ms
Memory:222476 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
using namespace std;
typedef long long LL;
const int N = 51000, inf = 1 << 29;
struct node { int x, y, n; } a[N];
struct Edge { int y, nex, z; } g[N*20];
int n, sz = 1, pos[N], f[N], d[N], out[N], S, T, ans, pr[N][5], lx[N], ly[N], py[N][1002], que[N], dis[N], so, si, in[N];
int sum, hd, tl; bool va[N][2], nof[N];
map<int, int> m1, m2, mx;
void Init(int x, int y, int z) { g[++ sz] = (Edge) { y, pos[x], z }, pos[x] = sz; }
void Add(int x, int y, int z) { Init(x, y, z), Init(y, x, 0); }
bool cmp(node x, node y) { return (x.y == y.y) ? x.x < y.x : x.y < y.y; }
void Renew(int x, int &z) {
if (z) {
if (f[x] <= d[z]) f[x] = d[z] + 1, pr[x][ lx[x] = 1 ] = z;
else if (f[x] == d[z] + 1) pr[x][++ lx[x]] = z;
}
z = x;
}
void Print(int x, bool ty) {
if (!x) return ;
if (ty) {
int y = py[x][1]; Print(y, 0);
if (x == y) return ;
if (y < x) {
for (int z = y - 1; a[z].y == a[y].y; z --) printf("%d ", a[z].n);
Rep(z, y + 1, x) printf("%d ", a[z].n);
} else {
for (int z = y + 1; a[z].y == a[y].y; z ++) printf("%d ", a[z].n);
Dwn(z, y - 1, x) printf("%d ", a[z].n);
}
} else Print(pr[x][1], 1), printf("%d ", a[x].n);
}
void Build(int x, bool ty) {
if (!x || va[x][ty]) return ;
va[x][ty] = 1;
if (ty) Rep(i, 1, ly[x]) Build(py[x][i], 0);
else Rep(i, 1, lx[x]) { int y = pr[x][i]; out[y] ++, in[x] ++, Build(y, 1), Add(y, x, inf); }
}
bool Bfs() {
memset(dis, 0, sizeof(dis)), dis[S] = 1;
que[hd = tl = 1] = S;
while (hd <= tl) {
int x = que[hd ++];
RepE(i, x) {
int y = g[i].y;
if (!dis[y] && g[i].z) dis[y] = dis[x] + 1, que[++ tl] = y;
}
}
return dis[T];
}
int Dfs(int x, int mx) {
if (x == T) return mx;
if (nof[x]) return 0;
int ret = 0;
RepE(i, x) {
int y = g[i].y, k;
if (mx && dis[y] == dis[x] + 1 && g[i].z && (k = Dfs(y, min(mx, g[i].z)))) {
ret += k, g[i].z -= k, g[i ^ 1].z += k, mx -= k;
}
}
if (!ret) nof[x] = 1;
return ret;
}
void Dinic() {
int ret = 0;
while (Bfs()) {
memset(nof, 0, sizeof(nof));
while (ret = Dfs(S, inf)) sum -= ret;
}
}
int main()
{
scanf ("%d", &n), S = n + 1, T = n + 2;
Rep(i, 1, n) scanf ("%d%d", &a[i].x, &a[i].y), a[i].n = i;
sort(a + 1, a + n + 1, cmp);
for (int i = 1, lt = 0; i <= n; i = lt + 1) {
while (lt < n && a[lt + 1].y == a[i].y) {
lt ++; int x = a[lt].x, y = a[lt].y;
if (x == y || x == -y || !x) f[lt] = 1, pr[lt][ lx[lt] = 1 ] = 0; else f[lt] = -n;
Renew(lt, mx[x]), Renew(lt, m1[x + y]), Renew(lt, m2[x - y]);
}
int w;
Rep(j, i, lt) {
w = f[j]; py[j][ ly[j] = 1 ] = j;
Rep(k, i, j - 1)
if (f[k] + j - i > w) w = f[k] + j - i, py[j][ ly[j] = 1 ] = k;
else if (f[k] + j - i == w) py[j][ ++ ly[j] ] = k;
d[j] = w;
}
Dwn(j, lt, i) {
w = d[j];
Rep(k, j + 1, lt)
if (f[k] + lt - j > w) w = f[k] + lt - j, py[j][ ly[j] = 1 ] = k;
else if (f[k] + lt - j == w) py[j][ ++ ly[j] ] = k;
d[j] = w; ans = max(ans, w);
}
}
printf("%d\n", ans);
Rep(i, 1, n) if (d[i] == ans) { Print(i, 1); puts(""); break ; }
Rep(i, 1, n) if (d[i] == ans) Build(i, 1);
Rep(i, 0, n) {
if (in[i] > out[i]) Add(S, i, in[i] - out[i]), sum += in[i] - out[i];
else Add(i, T, out[i] - in[i]);
}
Dinic();
printf("%d\n", sum);
return 0;
}