单独用扫描线计算竖线与横线的并(部分1),并暴力容斥斜线与斜线的并(部分2),再减掉两个部分的交集的部分。
其中部分1的计算我是复制的扫描线的板子,应该没什么问题,试过有95分的。
感觉是部分2的计算:或者计算两个部分的交集的交集有问题,麻烦大佬帮忙看看。
部分2的计算:
void dfs(int k) { //容斥计算斜线本身的并
if(k > hh) {
int z = -1;
int len = 0;
int LL = 0, RR = 1e18;
for(int i = 1; i <= hh; i++) {
if(now[i] == 0) continue;
len++;
int u = R[i].Y1 - R[i].X1;
if(z == -1) {
z = u;
}
else if(z != u) {
return;
}
LL = max(LL, R[i].X1);
RR = min(RR, R[i].X2);
}
if(LL > RR || LL == 0 && RR == 1e18) return;
if(len % 2 == 1) ans += (RR - LL + 1);
else ans -= (RR - LL + 1);
return;
}
now[k] = 1;
dfs(k + 1);
now[k] = 0;
dfs(k + 1);
}
交集的计算:
for(int i = 1; i <= hh; i++) {
for(int j = 1; j <= nn; j++) { //暴力计算两不分的并
int b = R[i].Y1 - R[i].X1;
if(Y1[j] == Y2[j]) {
int xx = Y1[j] - b;
if(X1[j] <= xx && xx <= X2[j]) {
if(P[xx][Y1[j]] == 0) {
P[xx][Y1[j]] = 1;
ans--;
}
}
}
else if(X1[j] == X2[j]) {
int yy = X1[j] + b;
if(Y1[j] <= yy && yy <= Y2[j]) {
if(P[X1[j]][yy] == 0) {
P[X1[j]][yy] = 1;
ans--;
}
}
}
}
}
总代码:
#include<bits/stdc++.h>
#define int long long
#define N 500005
using namespace std;
int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar('0' + x % 10);
}
int n, m, q, ans, c;
int X1[N], Y1[N], X2[N], Y2[N];
int xx1[N], yy1[N], xx2[N], yy2[N];
int b1[N], cnt1, d1[N], len1;
int b2[N], cnt2, d2[N], len2;
struct Tree{
int Min[N * 4], c[N * 4], tag[N * 4]; //维护区间最小值以及区间最小值的个数
void pushup(int u) {
if(Min[u * 2] == Min[u * 2 + 1]) {
Min[u] = Min[u * 2];
c[u] = c[u * 2] + c[u * 2 + 1];
}
else if(Min[u * 2] < Min[u * 2 + 1]) {
Min[u] = Min[u * 2];
c[u] = c[u * 2];
}
else {
Min[u] = Min[u * 2 + 1];
c[u] = c[u * 2 + 1];
}
}
void maketag(int u, int L, int R, int x) {
Min[u] += x;
tag[u] += x;
}
void pushdown(int u, int L, int R) {
int mid = (L + R) / 2;
maketag(u * 2, L, mid, tag[u]);
maketag(u * 2 + 1, mid + 1, R, tag[u]);
tag[u] = 0;
}
void build(int u, int L, int R) {
tag[u] = 0;
if(L == R) {
Min[u] = 0;
c[u] = d1[R + 1] - d1[L];
return;
}
int mid = (L + R) / 2;
build(u * 2, L, mid);
build(u * 2 + 1, mid + 1, R);
pushup(u);
}
void update(int u, int L, int R, int l, int r, int x) {
if(R < l || r < L) return;
if(l <= L && R <= r) {
maketag(u, L, R, x * (d1[R + 1] - d1[L]));
return;
}
int mid = (L + R) / 2;
pushdown(u, L, R);
update(u * 2, L, mid, l, r, x);
update(u * 2 + 1, mid + 1, R, l, r, x);
pushup(u);
}
int query(int u, int L, int R, int l, int r) {
if(R < l || r < L) return 0;
if(l <= L && R <= r) {
if(Min[u] != 0) return d1[R + 1] - d1[L];
else return d1[R + 1] - d1[L] - c[u];
}
int mid = (L + R) / 2;
pushdown(u, L, R);
return query(u * 2, L, mid, l, r), query(u * 2 + 1, mid + 1, R, l, r);
}
}t;
struct node{
int opt, L, R;
};
vector<node>Q[N];
struct End{
int X1, Y1, X2, Y2;
}R[N];
int hh = 0;
unordered_map<int, unordered_map<int, int>>P;
bool now[N];
void dfs(int k) { //容斥计算斜线本身的并
if(k > hh) {
int z = -1;
int len = 0;
int LL = 0, RR = 1e18;
for(int i = 1; i <= hh; i++) {
if(now[i] == 0) continue;
len++;
int u = R[i].Y1 - R[i].X1;
if(z == -1) {
z = u;
}
else if(z != u) {
return;
}
LL = max(LL, R[i].X1);
RR = min(RR, R[i].X2);
}
if(LL > RR || LL == 0 && RR == 1e18) return;
if(len % 2 == 1) ans += (RR - LL + 1);
else ans -= (RR - LL + 1);
return;
}
now[k] = 1;
dfs(k + 1);
now[k] = 0;
dfs(k + 1);
}
signed main() {
c = read();
n = read(); m = read(); q = read();
int nn = 0;
for(int i = 1; i <= q; i++) {
int opt = read();
if(opt <= 2) {
nn++;
X1[nn] = read(); Y1[nn] = read();
X2[nn] = read() + 1; Y2[nn] = read() + 1;
b1[++cnt1] = Y1[nn]; b2[++cnt2] = X1[nn];
b1[++cnt1] = Y2[nn]; b2[++cnt2] = X2[nn];
}
else {
hh++;
R[hh].X1 = read(); R[hh].Y1 = read();
R[hh].X2 = read(); R[hh].Y2 = read();
}
} //b1存y,b2存x
dfs(1);
sort(b1 + 1, b1 + cnt1 + 1);
sort(b2 + 1, b2 + cnt2 + 1);
for(int i = 1; i <= cnt1; i++)
if(i == 1 || b1[i] != b1[i - 1]) d1[++len1] = b1[i];
for(int i = 1; i <= cnt2; i++)
if(i == 1 || b2[i] != b2[i - 1]) d2[++len2] = b2[i];
for(int i = 1; i <= nn; i++) {
xx1[i] = lower_bound(d2 + 1, d2 + len2 + 1, X1[i]) - d2;
yy1[i] = lower_bound(d1 + 1, d1 + len1 + 1, Y1[i]) - d1;
xx2[i] = lower_bound(d2 + 1, d2 + len2 + 1, X2[i]) - d2;
yy2[i] = lower_bound(d1 + 1, d1 + len1 + 1, Y2[i]) - d1;
Q[xx1[i]].push_back((node){1, yy1[i], yy2[i]});
Q[xx2[i]].push_back((node){-1, yy1[i], yy2[i]});
}
t.build(1, 1, len1 - 1);
for(int i = 1; i <= len2 - 1; i++) {
for(int k = 0; k < Q[i].size(); k++) {
node cmp = Q[i][k];
t.update(1, 1, len1 - 1, cmp.L, cmp.R - 1, cmp.opt);
}
ans += (d2[i + 1] - d2[i]) * t.query(1, 1, len1 - 1, 1, len1 - 1);
} //扫描线计算横线和竖线本身的并
for(int i = 1; i <= nn; i++) X2[i]--, Y2[i]--;
for(int i = 1; i <= hh; i++) {
for(int j = 1; j <= nn; j++) { //暴力计算两不分的并
int b = R[i].Y1 - R[i].X1;
if(Y1[j] == Y2[j]) {
int xx = Y1[j] - b;
if(X1[j] <= xx && xx <= X2[j]) {
if(P[xx][Y1[j]] == 0) {
P[xx][Y1[j]] = 1;
ans--;
}
}
}
else if(X1[j] == X2[j]) {
int yy = X1[j] + b;
if(Y1[j] <= yy && yy <= Y2[j]) {
if(P[X1[j]][yy] == 0) {
P[X1[j]][yy] = 1;
ans--;
}
}
}
}
}
write(ans);
return 0;
}
/*
0
5 5 3
1 1 3 5 3
2 3 1 3 5
3 1 1 5 5
*/