##题面
链接_洛谷
链接_CF
简述一下题意:
在一个 n ∗ n ( n ≤ 10000 ) n*n(n\leq10000) n∗n(n≤10000)的棋盘上放棋子,要求一行一列不能放两个棋子。现在删去 n n n个矩形,输入方式是给左下坐标和右上坐标。删去的矩形不能放棋子,但棋子隔着一个删去的矩形仍然会互相干扰。求最多放几个棋子。
##分析
首先考虑放棋子是什么意思(这是一个挺常见的转化),一行和一列去配对,每一行每一列只能配对一次。删去的部分就是这些行和这些列不可以配对。
连10000*10000条边显然要超时炸空间,那么我们考虑线段树优化建图。不了解优化建图的建议出门百度网络流优化建图。但是这个时候遇到一个问题,就是优化建图是一段区间向一段区间连边,但是我们只知道一段区间不能和一段区间连边。所以考虑如何把剩余部分划分成若干矩形。
一种十分容易想到的方式是直接从所有删掉的矩形的边那里切开(如图,红色是删掉的部分),然而如果删掉的是一条对角线上的所有矩形这就变暴力了TAT。
我们观察一下这个切分方式:我们切分了很多无用的线,对于在它上面很多的矩形切下来的线,完全可以置之不理。
于是我们考虑扫描线。具体步骤如下:对于每一个矩形的下边,它以下部分切一个矩形出来。对于一个矩形的上边,左右两侧切两个矩形出来。如图。
现在来考察复杂度:对于每个矩形,遇到底边的时候出现一个矩形,顶边的时候出现两个矩形,于是我们一共会剖分 O ( n ) O(n) O(n)个矩形,可以接受。
细节有点麻烦,以后有功夫了上来写一下
代码
十分晦涩qwq
因为自己改了好多遍,拍出了无数错和没考虑好的地方所以就十分丑陋
以后也许会来补一补注释什么的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <math.h>
#include <set>
#include <ctime>
#define MAXN 10050
#define INF (1<<28)
#define LLINF (1LL<<40)
#define LL long long
#define ri register int
using namespace std;
int n, Q, maxx, cnt, ecnt, tot, S, T;
int q[MAXN<<6], level[MAXN<<3], Cnt[2], interval[2][MAXN], ppos[MAXN];
/*The first line contains single integer n ( 1<=n<=10000 ) — the size of the board.
The second line contains single integer q ( 0<=q<=10000 ) — the number of deleted rectangles.
The next q lines contain the information about the deleted rectangles.
Each of these lines contains four integers x1 y1, x2 y2;
the coordinates of the lower left and the upper right cells of a deleted rectangle.*/
struct Node {
int l, r, h, ty, hh;
bool operator < (const Node &x) const {
if(h == x.h && ty == x.ty) return r < x.r;
if(h == x.h) return ty > x.ty;
return h < x.h;
}
}line[MAXN*3];
struct NODE {
int pos, lhh, rhh, high;
bool operator < (const NODE &x) const {
return pos < x.pos;
}
};
struct node {
int v, c; node *next, *rev;
}pool[MAXN*1000], *h[MAXN<<5], *cur[MAXN<<5];
set <NODE> s;
inline void addedge(int u, int v, int c) {
node *p = &pool[ecnt++], *q = &pool[ecnt++];
*p = node{
v, c