我的妈呀,这码农神题......

第一问是个DP,要记录方案。先把纵向的转移建图。发现可以按照y坐标来划分阶段,每一层vector存一下,用前后缀最大值来转移。

第二问考虑所有可能成为最优方案的边。从终点倒推可以保证每条边都能到起点,而从起点出发就不一定能保证。这些边拿去网络流建图,然后最小流。

注意第二问找边的时候,每一层的点其实可以视作两个,经过同层转移的和未经过的。这两者不可混为一谈。

最小流先跑S -> T然后t -> s退流的话,要用当前弧优化,否则会被最后一个数据卡成n²。

 #include <bits/stdc++.h>

 const int N = , INF = 0x7f7f7f7f;

 struct Node {
int x, y, id;
inline bool operator <(const Node &w) const {
if(y != w.y) return y < w.y;
return x < w.x;
}
}node[N]; inline void read(int &x) {
x = ;
char c = getchar();
bool f = ;
while(c < '' || c > '') {
if(c == '-') f = ;
c = getchar();
}
while(c >= '' && c <= '') {
x = x * + c - ;
c = getchar();
}
if(f) x = (~x) + ;
return;
} struct Edge {
int nex, v;
}edge[N << ]; int tp; int n, X[N << ], xx, bin[N << ], e[N], fr1[N], fr2[N], fr_l[N], fr_r[N], large_l[N], large_r[N], f[N], ff[N];
bool visit[N], visit2[N];
std::vector<int> v[N << ]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void out(int x, int flag) {
if(!node[x].id) return;
if(flag == ) {
out(fr1[x], );
}
else {
out(fr2[x], );
int y = fr2[x], u = node[y].y;
if(y == x) {
printf("%d ", node[x].id);
}
else if(node[y].x > node[x].x) {
for(int i = ; i < (int)(v[u].size()); i++) {
if(node[v[u][i]].x >= node[y].x) {
printf("%d ", node[v[u][i]].id);
}
}
for(int i = v[u].size() - ; i >= ; i--) {
int temp = node[v[u][i]].x;
if(temp < node[y].x && temp >= node[x].x) {
printf("%d ", node[v[u][i]].id);
}
}
}
else {
for(int i = v[u].size() - ; i >= ; i--) {
if(node[v[u][i]].x <= node[y].x) {
printf("%d ", node[v[u][i]].id);
}
}
for(int i = ; i < (int)(v[u].size()); i++) {
int temp = node[v[u][i]].x;
if(temp > node[y].x && temp <= node[x].x) {
printf("%d ", node[v[u][i]].id);
}
}
}
}
return;
} namespace fl {
struct Edge {
int nex, v, c;
Edge(int Nex = , int V = , int C = ) {
nex = Nex;
v = V;
c = C;
}
}edge[]; int tp = ;
int e[N], vis[N], in[N], d[N], vis2[N], cur[N];
std::queue<int> Q;
inline void add(int x, int y, int z) {
edge[++tp] = Edge(e[x], y, z);
e[x] = tp;
edge[++tp] = Edge(e[y], x, );
e[y] = tp;
return;
}
inline void Add(int x, int y) {
/// x -> y [1, INF]
vis2[x] = vis2[y] = ;
add(x, y, N);
in[y]++;
in[x]--;
return;
}
inline bool BFS(int s, int t) {
static int Time = ; Time++;
vis[s] = Time;
d[s] = ;
Q.push(s);
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(vis[y] != Time && edge[i].c) {
vis[y] = Time;
d[y] = d[x] + ;
Q.push(y);
}
}
}
return vis[t] == Time;
}
int DFS(int x, int t, int maxF) {
if(x == t) return maxF;
int ans = ;
for(int i = cur[x] ? cur[x] : e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(!edge[i].c || d[y] != d[x] + ) {
continue;
}
int temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
if(!temp) d[y] = INF;
ans += temp;
edge[i].c -= temp;
edge[i ^ ].c += temp;
if(ans == maxF) break;
cur[x] = i;
}
return ans;
}
inline int dinic(int s, int t) {
int ans = ;
while(BFS(s, t)) {
memset(cur, , sizeof(cur));
ans += DFS(s, t, INF);
}
return ans;
}
inline void solve() {
int s = N - , t = N - , S = N - , T = N - ;
for(int i = ; i <= n; i++) {
if(!vis2[i]) continue;
add(s, i, N);
add(i, t, N);
}
int now = tp;
add(t, s, INF);
for(int i = ; i <= n; i++) {
if(in[i] > ) {
add(S, i, in[i]);
}
else if(in[i] < ) {
add(i, T, -in[i]);
}
}
int ans;
dinic(S, T);
ans = edge[now + ].c;
for(int i = now + ; i <= tp; i++) edge[i].c = ;
ans -= dinic(t, s);
printf("%d\n", ans);
return;
}
} int main() {
read(n);
for(int i = ; i <= n; i++) {
read(node[i].x); read(node[i].y);
node[i].id = i;
X[++xx] = node[i].x;
X[++xx] = node[i].y;
X[++xx] = node[i].x + node[i].y;
X[++xx] = node[i].x - node[i].y;
}
++n; ++xx; /// the Node O
std::sort(node + , node + n + );
std::sort(X + , X + xx + );
xx = std::unique(X + , X + xx + ) - X - ;
for(int i = ; i <= n; i++) {
int temp = std::lower_bound(X + , X + xx + , node[i].x + node[i].y) - X;
if(bin[temp]) {
add(bin[temp], i);
}
bin[temp] = i;
}
memset(bin + , , xx * sizeof(int));
for(int i = ; i <= n; i++) {
int temp = std::lower_bound(X + , X + xx + , node[i].x - node[i].y) - X;
if(bin[temp]) {
add(bin[temp], i);
}
bin[temp] = i;
}
memset(bin + , , xx * sizeof(int));
for(int i = ; i <= n; i++) {
node[i].x = std::lower_bound(X + , X + xx + , node[i].x) - X;
node[i].y = std::lower_bound(X + , X + xx + , node[i].y) - X;
}
for(int i = ; i <= n; i++) {
if(bin[node[i].x]) {
add(bin[node[i].x], i);
}
bin[node[i].x] = i;
v[node[i].y].push_back(i);
}
/// Build Graph 1 Over
memset(f, ~0x3f, sizeof(f));
f[] = ;
for(int u = ; u <= xx; u++) {
if(!v[u].size()) continue;
int len = v[u].size();
for(int i = ; i < len; i++) {
int x = v[u][i];
ff[x] = f[x];
fr2[x] = x;
}
/// trans in row
for(int i = ; i < len; i++) {
int x = v[u][i];
if(i && f[x] < large_l[i - ]) {
large_l[i] = large_l[i - ];
fr_l[i] = fr_l[i - ];
}
else {
large_l[i] = f[x];
fr_l[i] = x;
}
}
for(int i = len - ; i >= ; i--) {
int x = v[u][i];
if(i < len - && f[x] < large_r[i + ]) {
large_r[i] = large_r[i + ];
fr_r[i] = fr_r[i + ];
}
else {
large_r[i] = f[x];
fr_r[i] = x;
}
}
for(int i = ; i < len; i++) {
int x = v[u][i];
if(i < len - && f[x] < large_r[i + ] + len - i - ) {
f[x] = large_r[i + ] + len - i - ;
fr2[x] = fr_r[i + ];
}
if(i && f[x] < large_l[i - ] + i) {
f[x] = large_l[i - ] + i;
fr2[x] = fr_l[i - ];
}
}
/// trans in cross / other
for(int i = ; i < len; i++) {
int x = v[u][i];
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(f[y] < f[x] + ) {
f[y] = f[x] + ;
fr1[y] = x;
}
}
}
}
/// DP OVER
int large_val = -INF, ans_pos = ;
for(int i = ; i <= n; i++) {
if(large_val < f[i]) {
large_val = f[i];
ans_pos = i;
}
}
printf("%d\n", large_val);
out(ans_pos, );
/// Out OVER
for(int i = ; i <= n; i++) {
if(f[i] == large_val) visit2[i] = ;
if(ff[i] == large_val) visit[i] = ;
}
for(int u = xx; u >= ; u--) {
if(!v[u].size()) continue;
int len = v[u].size();
/// build Flow Graph (this -> up)
for(int i = ; i < len; i++) {
int x = v[u][i];
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(visit[y] && ff[y] == f[x] + ) {
visit2[x] = ;
fl::Add(x, y);
}
}
if(visit2[x] && f[x] == ff[x]) {
visit[x] = ;
}
}
/// Find Edge in row (update)
for(int j = ; j < len; j++) {
int y = v[u][j];
if(!visit2[y]) continue;
for(int i = ; i < len; i++) {
int x = v[u][i];
if(visit[x]) continue;
/// x -> y
if(node[x].x < node[y].x && f[y] == ff[x] + j) {
visit[x] = ;
}
else if(node[y].x < node[x].x && f[y] == ff[x] + len - j - ) {
visit[x] = ;
}
}
}
}
puts("");
/// Build Flow Over
fl::solve();
return ;
}

AC代码

10k还行

LOJ#2134 小园丁与老司机的更多相关文章

  1. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  2. [BZOJ4200][Noi2015]小园丁与老司机

    4200: [Noi2015]小园丁与老司机 Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 106  Solved ...

  3. 【BZOJ4200】【NOI2015】小园丁与老司机(动态规划,网络流)

    [BZOJ4200][NOI2015]小园丁与老司机(动态规划,网络流) 题面 BZOJ权限题,洛谷链接 题解 一道二合一的题目 考虑第一问. 先考虑如何计算六个方向上的第一个点. 左右上很好考虑,只 ...

  4. [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机

    [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机 试题描述 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 \(n\) 棵许愿 ...

  5. 【BZOJ4200】[Noi2015]小园丁与老司机 DP+最小流

    [BZOJ2839][Noi2015]小园丁与老司机 Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2, ...

  6. 「NOI2015」小园丁与老司机

    「NOI2015」小园丁与老司机 要不是这道码农题,去年就补完了NOI2015,其实两问都比较simple,但是写起来很恶心. 先解决第一问,记 \(dp[i]\) 表示老司机到达第 \(i\) 棵树 ...

  7. luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流

    LINK:小园丁与老司机 苦心人 天不负 卧薪尝胆 三千越甲可吞吴 AC的刹那 真的是泪目啊 很久以前就写了 当时记得特别清楚 写到肚子疼.. 调到胳膊疼.. ex到根不不想看的程度. 当时wa了 一 ...

  8. 【洛谷2304_LOJ2134】[NOI2015]小园丁与老司机(动态规划_网络流)

    题目: 洛谷 2304 LOJ 2134 (LOJ 上每个测试点有部分分) 写了快一天 -- 好菜啊 分析: 毒瘤二合一题 -- 注意本题(及本文)使用 \(x\) 向右,\(y\) 向上的「数学坐标 ...

  9. [BZOJ]4200: [Noi2015]小园丁与老司机

    Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special Judge Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维 ...

随机推荐

  1. w3c JS测试

    到W3c的js测试里面溜达了一圈: 做错了几道题: 外部脚本必须包含<script>标签吗? 否!! 这里的外部脚本是指xx.js这个文件,在文件中写js代码是不需要包含script标签的 ...

  2. 【gedit】 显示行号

    打开gedit文本编辑器->Edit(编辑)->preferences(预设)->view(视图)->在Display line numbers前打勾->close

  3. linux之nload和iftop查看网络使用情况

    操作系统: centos7 nload: yum install -y gcc yum install -y gcc-c++ yum install -y ncurses-devel yum inst ...

  4. Java反射交换两个整型变量的值

    在一次面试中,做了这么一道题"交换两个整型变量的值",当时看到这个题目之后,会心一笑,这也太简单了--直接使用中间变量交换不就可以了吗?但是,面试官却说不需要返回值,在调用的地方, ...

  5. indexOf刚开始写成IndexOf出错

    {{# if(d.fronturlmin ==null||d.fronturlmin ==""){ }} <img src="@System.Configurati ...

  6. 皮皮虾FAQ

    我们提供的软件,是市场上比较好操作的,如果有其他的软件也是可以使用我们的ip的 Windows 1.windows找不到粘贴的地方 window打开窗口后,请在屏幕右下角找小飞机,右键即可 2.win ...

  7. 小程序 official-account

    只需要在页面中添加 <official-account></official-account> 需要注意的是: 1.当小程序从扫二维码场景(场景值1011)打开时 2.当小程序 ...

  8. kubernetes 每个node上只能运行一个副本DaemonSet

    每个node上只能运行一个副本: apiVersion: extensions/v1beta1 kind: DaemonSet #使用DaemonSet的方式运行 metadata: name: ku ...

  9. Power Network POJ - 1459 网络流 DInic 模板

    #include<cstring> #include<cstdio> #define FOR(i,f_start,f_end) for(int i=f_startl;i< ...

  10. Basic remains POJ - 2305 同余模 高精度处理

    题意 给出B(10以内大于0)进制下 p (1000位以内)和m(9位以内) 求 p%m 在b进制下等于什么 思路: 可以计算   1e9不会溢出Int所以m在int值以内  先求m  要处理p  每 ...