首页 > 其他分享 >P8734 奇偶覆盖 题解

P8734 奇偶覆盖 题解

时间:2024-08-16 16:49:02浏览次数:14  
标签:奇偶 return Ytot int 题解 void P8734 add rec

Statement

矩形面积并,但是覆盖奇数次、覆盖偶数次的面积要分别输出。

Solution

提供一种不费脑子的做法:

首先离散化、扫描线,问题变成维护区间 +1-1、询问全局有多少正数是奇数、多少正数是偶数。

若去除“正数”的条件,这是很容易用一个标记下传的线段树维护的,区间分别维护 0,1 个数、加法标记,一个区间 +1 或 -1 就 swap(cnt0, cnt1)

但是有“正数”的条件,这时偶数的答案需要减去 0 的数量,而“区间 +1-1、询问全局 0 的数量”就用原版扫描线线段树的方法来维护就行了!

所以我们维护两棵线段树,一棵标记下传,一棵不下传,分别维护奇偶数的数量、0 的数量,修改时两棵线段树同步修改即可。

时间 \(O(n\log n)\)。

代码很可读:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
struct Rec {
	int Lx, Ly, Rx, Ry;
} rec[N];
int n;

struct Operation {
	int L, R, x, add;
} Ops[N];
int optot;

int Ytot, Y[N];

namespace SegA {
	int len[N << 2], add[N << 2], zero[N << 2];
#define lc (u << 1)
#define rc ((u << 1) | 1)
#define mid ((l + r) >> 1)
	void up(int u) {
		if (add[u]) {
			zero[u] = 0;
		} else {
			zero[u] = zero[lc] + zero[rc];
		}
	}
	void build(int u, int l, int r) {
		len[u] = Y[r + 1] - Y[l];
		zero[u] = len[u];
		add[u] = 0;
		if (l == r) return;
		build(lc, l, mid), build(rc, mid + 1, r);
	}
	void upd(int u, int l, int r, int x, int y, int v) {
		if (y < l || r < x) return;
		if (x <= l && r <= y) {
			add[u] += v;
			if (add[u]) {
				zero[u] = 0;
			} else {
				if (l == r) zero[u] = len[u];
				else zero[u] = zero[lc] + zero[rc];
			}
			return;
		}
		upd(lc, l, mid, x, y, v), upd(rc, mid + 1, r, x, y, v), up(u);
	}
#undef lc
#undef rc
#undef mid
}
namespace SegB {
	int len[N << 2], add[N << 2], odd[N << 2], even[N << 2];
#define lc (u << 1)
#define rc ((u << 1) | 1)
#define mid ((l + r) >> 1)
	void up(int u) {
		odd[u] = odd[lc] + odd[rc];
		even[u] = even[lc] + even[rc];
	}
	void Add(int u) {
		add[u] ^= 1, swap(odd[u], even[u]);
	}
	void down(int u) {
		if (add[u]) Add(lc), Add(rc), add[u] ^= 1;
	}
	void build(int u, int l, int r) {
		len[u] = Y[r + 1] - Y[l], add[u] = 0, odd[u] = 0, even[u] = len[u];
		if (l == r) return;
		build(lc, l, mid), build(rc, mid + 1, r);
	}
	void upd(int u, int l, int r, int x, int y) {
		if (y < l || r < x) return;
		if (x <= l && r <= y) return Add(u);
		down(u), upd(lc, l, mid, x, y), upd(rc, mid + 1, r, x, y), up(u);
	}
#undef lc
#undef rc
#undef mid
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr);
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> rec[i].Lx >> rec[i].Ly >> rec[i].Rx >> rec[i].Ry;
		Y[++Ytot] = rec[i].Ly, Y[++Ytot] = rec[i].Ry;
		Ops[++optot] = (Operation){rec[i].Ly, rec[i].Ry, rec[i].Lx, 1};
		Ops[++optot] = (Operation){rec[i].Ly, rec[i].Ry, rec[i].Rx, -1};
	}
	sort(Y + 1, Y + Ytot + 1);
	Ytot = unique(Y + 1, Y + Ytot + 1) - Y - 1;
	auto GetY = [&](int y) {
		return lower_bound(Y + 1, Y + Ytot + 1, y) - Y;
	};
	sort(Ops + 1, Ops + optot + 1, [&](Operation u, Operation v) -> bool {
		return u.x == v.x ? u.add > v.add : u.x < v.x;
	});
	for (int i = 1; i <= optot; ++i) 
		Ops[i].L = GetY(Ops[i].L), Ops[i].R = GetY(Ops[i].R) - 1;
	--Ytot;
	SegA::build(1, 1, Ytot);
	SegB::build(1, 1, Ytot);
	ll Odd = 0, Even = 0;
	for (int i = 1; i <= optot; ++i) {
		SegA::upd(1, 1, Ytot, Ops[i].L, Ops[i].R, Ops[i].add);
		SegB::upd(1, 1, Ytot, Ops[i].L, Ops[i].R);
		if (Ops[i].x != Ops[i + 1].x && i != optot) {
			ll len = Ops[i + 1].x - Ops[i].x;
			Odd += len * SegB::odd[1];
			Even += len * (SegB::even[1] - SegA::zero[1]);
		}
	}
	cout << Odd << '\n' << Even << '\n';
	return 0;
}


标签:奇偶,return,Ytot,int,题解,void,P8734,add,rec
From: https://www.cnblogs.com/laijinyi/p/18363191

相关文章

  • Git 命令大全:详细讲解与常见问题解决方案
    目录1.Git基础命令2.分支管理命令3.远程仓库管理命令4.标签管理命令5.其他常用命令6.总结Git是目前最流行的分布式版本控制系统,它使得团队协作和代码管理变得更加高效。本文将详细介绍Git的常用命令及其应用场景,并针对可能遇到的问题提供解决方案。1.Git......
  • P8518 [IOI2021] 分糖果 题解
    DescriptionKhong阿姨正在给附近一所学校的学生准备\(n\)盒糖果。盒子的编号分别为\(0\)到\(n-1\),开始时盒子都为空。第\(i\)个盒子\((0\leqi\leqn-1)\)至多可以容纳\(c[i]\)块糖果(容量为\(c[i]\))。Khong阿姨花了\(q\)天时间准备糖果盒。在第\(j\)天......
  • [CEOI2009] photo 题解
    前言题目链接:洛谷。好多错解都被我叉了,所以来贡献一发正确的题解,并予以解释。题意简述平面上有\(n\)个点,现在要求用最少的底边在\(x\)轴上且面积小于等于\(S\)的矩形覆盖所有点,这些矩形可以重叠。问最少矩形数量。矩形顶点不必是整点。\(n\leq100\)。题目分析没什......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    题目传送门前置知识树链剖分|树的直径|最近公共祖先|并查集解法正着删边不太可做,考虑离线下来反着加边。一个显而易见的结论:设点集\(A\)的直径的两个端点为\(u_{1},v_{1}\),另一个点集\(B\)的直径的两个端点为\(u_{2},v_{2}\),则\(A\bigcupB\)的直径端点一定是......
  • 启动应用程序出现pcsvDevice.dll找不到问题解决
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个pcsvDevice.dll文件(挑选合适的版本文件)把......
  • P6109 [Ynoi2009] rprmq1 题解
    Description有一个\(n\timesn\)的矩阵\(a\),初始全是\(0\),有\(m\)次修改操作和\(q\)次查询操作,先进行所有修改操作,然后进行所有查询操作。一次修改操作会给出\(l_1,l_2,r_1,r_2,x\),代表把所有满足\(l_1\lei\ler_1\)且\(l_2\lej\ler_2\)的\(a_{i,j}\)元......
  • 题解:P10688 Buy Tickets
    题目大意排队时有人插队。输入格式给定队列长度$n$。接下来$n$行每行两个正整数,第一个表示该元素插入位置,另一个表示该元素的权值。输出格式按照顺序输出该位置元素的权值。注意事项输入的数据组数未知,需要一直输入,输入方法可以参考以下代码。while(cin>>n){......
  • 题解:P10781 【MX-J1-T1】『FLA - III』Spectral
    P10781【MX-J1-T1】『FLA-III』Spectral题解(非正解,正解应该是数学题。)这道题很简单,分析题意就可以得出核心代码:for(inti=1;i<=n;i++){ans=k+ans/i;}那么恭喜你获得$40$pts。为什么呢?因为题目需要的是最高温度,而烧碳获得的温度可能小于烧炭时减低的温度。简单说......
  • JOISC2020 Day 4 A 首都 题解
    JOISC2020Day4A首都JOIAtCoderLuogu考虑一条链的情形。如图,将每个城市视为一条线段,容易发现交错(有交但不包含)的若干线段必须全部合并才能符合条件。但如果这么写会出错,原因是线段有包含关系,外层线段需要统计内层线段的答案,但内层线段不需要统计外层线段的答案。如果设内......
  • 题解:AT_abc365_d [ABC365D] AtCoder Janken 3
    D-AtCoderJanken3题解题意:高桥和青木要玩石头剪刀布,给你一个长度为\(n\)的字符串\(s\),\(s\)表示青木在第\(i\)局游戏中的动作(R表示石头,P表示布,S表示剪刀。)。高桥不可以在任何一局中输给青木(即:高桥和青木只可以平局或高桥赢青木),且高桥第\(i\)局出的和第\(i-1\)局......