link。

调起来真的呕吐,网上又没篇题解。大概是个不错的题。

首先行和列一定是独立的,所以我们把行列分开考虑。这样的问题就弱化为:在一个长度为 \(n\) 的格子带上,有 \(n\) 个物品,每个物品 \(x\) 对应一个区间 \([l_x,r_x]\),分配每个物品的居所使得各住各的,求出其中的固定点。

把物品放在左部,把格子放在右部,即构造一个二部图。那么问题就是求出其最大匹配的必要边。先考虑如何求这个的最大匹配,这是个经典贪心吧,把每个区间按 \(l\) 排序,然后枚举位置,优先填入 \(r\) 小的物品。跑完后(即规定好方向后)对整个图跑缩点,两端点不在同一连通块的边即为必要边。

这个的边数是 \(O(n^2)\) 的,因为连边一下连一个区间,考虑利用这个来优化。线段树的高度不高吧,而且能够用来刻画一个区间,于是用这个东西来优化连边。

具体一点是,线段树上父亲对两个儿子连边,物品就对线段树上自己的区间连边即可。注意清空的时候带脑子……

#include<bits/stdc++.h>
using namespace std;
#define cmin(x, y) x = min(x, y)
#define cmax(x, y) x = max(x, y)
void eof(const char IO) {if(IO == -1) exit(0);}
template<typename T=int> T read() {
T x=0; char IO=getchar(); bool f=0; eof(IO);
while(IO<'0' || IO>'9') f|=IO=='-',eof(IO=getchar());
while(IO>='0' && IO<='9') x=x*10+(IO&15),eof(IO=getchar());
return f?-x:x;
}
int n,A[100100],B[100100],C[100100],D[100100],rec1[100100],rec2[100100],tot,ans1[100100],ans2[100100];
int col[400100],dfn[400100],low[400100],dfsnt,colnt,sta[400100],top,mat[400100],inst[400100];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
struct node{
int l,r,id;
friend bool operator<(const node& x,const node& y) {return x.l < y.l;}
} cur[100100];
vector<node> ans;
vector<vector<int>> e;
void DFS(const int now) {
inst[sta[++top] = now] = 1;
dfn[now] = low[now] = ++dfsnt;
for(const int y : e[now]) {
if(!dfn[y]) DFS(y),cmin(low[now], low[y]);
else if(inst[y]) cmin(low[now], dfn[y]);
}
if(low[now]^dfn[now]) return;
colnt++;
int y; do {
inst[y = sta[top--]] = 0;
col[y] = colnt;
} while(y != now);
}
#define mem(x, w, n) memset(x, w, n)
void sweep() {
e.clear();
mem(col, 0, min(size_t(n*4*30), sizeof(col)));
mem(dfn, 0, min(size_t(n*4*30), sizeof(dfn)));
mem(low, 0, min(size_t(n*4*30), sizeof(low)));
mem(sta, 0, min(size_t(n*4*30), sizeof(sta)));
mem(inst, 0, min(size_t(n*4*30), sizeof(inst)));
mem(mat, 0, min(size_t(n*4*30), sizeof(mat)));
// puts("DEBUGGING ----------");
// for(int* i : {col, dfn, low, sta, inst}) {
// for(int j = 0; j < 233; ++j) printf(" %d",i[j]);
// puts("");
// }
// puts("END___D__D__D____D___D_");
tot = dfsnt = colnt = top = 0;
while(q.size()) q.pop();
}
int tr[400100],reid[400100];
void addedge(const int one, const int ano) {
// printf("add:%d %d\n",one,ano);
if(one >= int(e.size())) e.resize(one+1);
e[one].push_back(ano);
}
void build(const int now, int l, int r) {
// printf(" %d %d\n",l,r);
tr[now] = ++tot;
if(l == r) return reid[l] = tot,void();
int mid = (l+r)>>1;
build(now<<1, l, mid),build(now<<1|1, mid+1, r);
addedge(tr[now], tr[now<<1]),addedge(tr[now], tr[now<<1|1]);
}
void lin(int x,int y,int k,const int now = 1,int l = 1,int r = n) {
if(l>y || r<x || x>y) return;
if(l>=x && r<=y) return addedge(k, tr[now]),void();
int mid = (l+r)>>1;
lin(x, y, k, now<<1, l, mid),lin(x, y, k, now<<1|1, mid+1, r);
}
bool solve(int rec[], int ans[]) {
sweep();
static int l[100100], r[100100];
for(int i=1; i<=n; ++i) l[i] = cur[i].l,r[i] = cur[i].r;
sort(cur + 1, cur + n + 1);
for(int i=1, p=1; i<=n; ++i) {
while(p <= n && cur[p].l <= i) q.emplace(cur[p].r, cur[p].id),p++;
if(!q.size() || q.top().first<i) return 0;
mat[q.top().second] = i;
q.pop();
}
tot = n;
build(1, 1, n);
// printf(" tot: %d\n", tot);
// for(int i=1; i<=4*n; ++i) printf(" %d",tr[i]);
// puts("");
for(int i=1; i<=n; ++i) {
addedge(reid[mat[i]], i);
lin(l[i], mat[i]-1, i);
lin(mat[i]+1, r[i], i);
}
for(int i=1; i<=tot; ++i) if(!dfn[i]) DFS(i);
// for(int i=1; i<=tot; ++i) printf(" %d",col[i]);
for(int i=1; i<=n; ++i) rec[i] = col[i] != col[reid[mat[i]]],ans[i] = mat[i];
return 1;
}
signed main() {
while(n = read(),233) {
for(int i=1; i<=n; ++i) A[i] = read(),B[i] = read(),C[i] = read(),D[i] = read();
for(int i=1; i<=n; ++i) cur[i] = (node){A[i], C[i], i};
if(!solve(rec1, ans1)) {
puts("-1");
goto Fail;
}
for(int i=1; i<=n; ++i) cur[i] = (node){B[i], D[i], i};
if(!solve(rec2, ans2)) {
puts("-1");
goto Fail;
}
vector<node>().swap(ans);
for(int i=1; i<=n; ++i) if(rec1[i] && rec2[i]) ans.push_back((node){i, ans1[i], ans2[i]});
cout<<ans.size()<<endl;
for(const auto [x, y, z] : ans) printf("%d %d %d\n", x, y, z);
Fail:;
}
return 0;
}

「openjudge / poj - 1057」Chessboard的更多相关文章

  1. 「POJ 3666」Making the Grade 题解(两种做法)

    0前言 感谢yxy童鞋的dp及暴力做法! 1 算法标签 优先队列.dp动态规划+滚动数组优化 2 题目难度 提高/提高+ CF rating:2300 3 题面 「POJ 3666」Making th ...

  2. LOJ6003 - 「网络流 24 题」魔术球

    原题链接 Description 假设有根柱子,现要按下述规则在这根柱子中依次放入编号为的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法 ...

  3. 对于前端,「微信小程序」其实不美好

    微信小程序开放公测了,9月底我曾经写过一篇 「微信小程序」来了,其中最后一句:"谢天谢地,我居然还是个前端". 这种火爆的新事物总是令人激动,感谢这个时代. 但是,当我真作为开发者 ...

  4. macOS安装「oh my zsh」

    目前常用的 Linux 系统和 OS X 系统的默认 Shell 都是 bash,但是真正强大的 Shell 是深藏不露的 zsh, 这货绝对是马车中的跑车,跑车中的飞行车,史称『终极 Shell』, ...

  5. 报名|「OneAPM x DaoCloud」技术公开课:Docker性能监控!

    如今,越来越多的公司开始 Docker 了,「三分之二的公司在尝试了 Docker 后最终使用了它」,也就是说 Docker 的转化率达到了 67%,同时转化时长也控制在 60 天内. 既然 Dock ...

  6. 企业运营对 DevOps 的「傲慢与偏见」

    摘要:出于各种原因,并非所有人都信任 DevOps .有些人觉得 DevOps 只不过给开发者改善产品提供了一个途径而已,还有的人觉得 DevOps 是一堆悦耳的空头支票,甚至有人认为 DevOps ...

  7. 「前端开发者」如何把握住「微信小程序」这波红利?

    由于前两周一直在老家处理重要事情,虽然朋友圈被「微信小程序」刷爆了,但并没有时间深入了解. 昨天回广州之后,第一件事情就是把「微信小程序」相关的文章.开发文档.设计规范全部看了一遍,基本上明白了「微信 ...

  8. 「花田对」CSDN程序员专场——谁来拯救技术宅!_豆瓣

    「花田对」CSDN程序员专场--谁来拯救技术宅!_豆瓣 「花田对」CSDN程序员专场--谁来拯救技术宅!

  9. Objective-C 实用关键字详解1「面试、工作」看我就 🐒 了 ^_^.

    在写项目 或 阅读别人的代码(一些优秀的源码)中,总能发现一些常见的关键字,随着编程经验的积累大部分还是知道是什么意思 的. 相信很多开发者跟我当初一样,只是基本的常用关键字定义属性会使用,但在关键字 ...

  10. LOJ6002 - 「网络流 24 题」最小路径覆盖

    原题链接 Description 求一个DAG的最小路径覆盖,并输出一种方案. Solution 模板题啦~ Code //「网络流 24 题」最小路径覆盖 #include <cstdio&g ...

随机推荐

  1. RabbitMQ快速使用代码手册

    本篇博客的内容为RabbitMQ在开发过程中的快速上手使用,侧重于代码部分,几乎没有相关概念的介绍,相关概念请参考以下csdn博客,两篇都是我找的精华帖,供大家学习.本篇博客也持续更新~~~ 内容代码 ...

  2. Go语言学习总结

    1. 跳出/执行下一次循环. {标签名}: for true { ... for true { ... break/continue {标签名} //默认不加标签,则跳出最近一层循环.加了标签可以跳出 ...

  3. 尚医通day13【预约挂号】(内附源码)

    页面预览 预约挂号 根据预约周期,展示可预约日期,根据有号.无号.约满等状态展示不同颜色,以示区分 可预约最后一个日期为即将放号日期 选择一个日期展示当天可预约列表 预约确认 第01章-预约挂号 接口 ...

  4. CSS3实现3D效果的图片墙

    先来看一下效果:http://39.105.101.122/myhtml/CSS/transform_3D/img_3D.html 目前没有做IE的兼容,在谷歌浏览器里面可以看到效果 布局结构: &l ...

  5. Python编程和数据科学中的大数据分析:如何从大量数据中提取有意义的信息和模式

    目录 <Python编程和数据科学中的大数据分析:如何从大量数据中提取有意义的信息和模式> 引言 大数据时代已经来临,随着互联网和物联网的普及,海量数据的产生和存储已经成为一种普遍的现象. ...

  6. IcedID恶意文档钓鱼手法剖析

    析 利用oletools静态分析,提取宏代码,如图: Function contents() With ActiveDocument.Content.Find loveDoor = .Execute( ...

  7. Java并发(十二)----线程应用之多线程解决烧水泡茶问题

    1.背景 统筹方法,是一种安排工作进程的数学方法.它的实用范围极广泛,在企业管理和基本建设中,以及关系复杂的科研项目的组织与管理中,都可以应用. 怎样应用呢?主要是把工序安排好. 比如,想泡壶茶喝.当 ...

  8. 【SpringBoot】条件装配 @profile

    profile 使用说明: @profile注解的作用是指定类或方法在特定的 Profile 环境生效,任何@Component或@Configuration注解的类都可以使用@Profile注解. ...

  9. 基于GPT搭建私有知识库聊天机器人(四)问答实现

    前文链接: 基于GPT搭建私有知识库聊天机器人(一)实现原理 基于GPT搭建私有知识库聊天机器人(二)环境安装 基于GPT搭建私有知识库聊天机器人(三)向量数据训练 在前面的文章中,我们介绍了如何使用 ...

  10. 一文详解 Okio 输入输出流

    在 OkHttp 的源码中,我们经常能看到 Okio 的身影,这篇文章,我们把Okio拿出来进行一个详细的介绍学习. 输入输出的概念简述 Okio 简介 工程中引入 Okio API 简介及使用介绍 ...