「JSOI2014」矩形并

传送门

我们首先考虑怎么算这个期望比较好。

我们不难发现每一个矩形要和 \(n - 1\) 个矩形去交,而总共又有 \(n\) 个矩形,所以我们把矩形两两之间的交全部加起来再除以 \(n(n - 1)\) 就是答案。

至于算矩形之间的交我们可以考虑把每个矩形都视为在这个矩形范围内区间加上 \(1\) ,那么我们只需要查询一个矩形内的和 - 该矩形自身的贡献就可以算出一个矩形与其他矩形的交。

所以现在相当于我们只需要实现二维的区间加/查询。

但是数据范围很大我们不可能用二维树状数组搞 不然这题就被爆艹了 。

所以我们考虑扫描线 + 一维树状数组来搞。

我们把纵坐标用树状数组维护起来,横坐标用扫描线代替。

对于每个矩形弄四条扫描线,两条修改两条查询。

其中一条修改在左边界加,另一条在右边界右边一个位置减。

其中一个查询在左边界左边一个位置算负的贡献,另一个在右边界算正的贡献。

那么有一个问题,为什么我们要对于左边界左边搞一条扫描线算负贡献呢?

我们考虑差分时的效果,我们对于一条加的修改扫描线,我们是把这条扫描线以左的一整块矩形区域都加了 \(1\)

那么我们如果在加之前,把一段区间的贡献减掉,实际上是减掉了若干个两个不同矩形左边界之间的值,那么我们这时如果在右边碰到一条查询正贡献的扫描线,我们会发现这两条扫描线的贡献一结合刚好就得到了一块矩形交的贡献,也就是说我们这样算就可以很方便地算矩形之间的交了。

具体细节可以手画一下图,那么我们接下来就用二维树状数组的实现技巧来搞。

还有一些小问题:运算过程中可能会爆 long long 所以我们用 long double 来存;然后就是树状数组不能以零为下标,所以我们再输入时把所有矩形的横纵坐标都往各正方向平移 \(2\) 个单位。

参考代码:

#include <algorithm>
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} typedef long double LL;
const int _ = 2e5 + 5, __ = 2e6 + 5; int n, num = 0; LL ans = 0;
struct node { int opt, x, l, r, v; } t[_ << 2];
inline bool cmp(const node& a, const node& b)
{ return a.x != b.x ? a.x < b.x : (a.opt != b.opt ? a.opt < b.opt : a.v < b.v); } struct BIT {
LL tr[__];
inline void update(int x, LL v) { for (rg int i = x; i < __; i += i & -i) tr[i] += v; }
inline LL query(int x) { LL res = 0; for (rg int i = x; i >= 1; i -= i & -i) res += tr[i]; return res; }
} tr1, tr2, tr3, tr4; inline void Update(int x, int y, int v) {
tr1.update(y, v), tr2.update(y, x * v), tr3.update(y, y * v), tr4.update(y, (LL) x * y * v);
} inline LL Query(int x, int y) {
return tr1.query(y) * (x + 1) * (y + 1) - tr2.query(y) * (y + 1) - tr3.query(y) * (x + 1) + tr4.query(y);
} int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n);
for (rg int x, y, a, b, i = 1; i <= n; ++i) {
read(x), read(y), read(a), read(b);
x += 2, y += 2;
t[++num] = (node) { 0, x, y, y + b - 1, 1 };
t[++num] = (node) { 0, x + a, y, y + b - 1, -1 };
t[++num] = (node) { 1, x - 1, y, y + b - 1, -1 };
t[++num] = (node) { 1, x + a - 1, y, y + b - 1, 1 };
ans -= 1ll * a * b;
}
sort(t + 1, t + num + 1, cmp);
for (rg int i = 1; i <= num; ++i) {
if (t[i].opt == 0)
Update(t[i].x, t[i].l, t[i].v), Update(t[i].x, t[i].r + 1, -t[i].v);
else
ans += t[i].v * (Query(t[i].x, t[i].r) - Query(t[i].x, t[i].l - 1));
}
printf("%.9Lf\n", 1.0 * ans / n / (n - 1));
return 0;
}

「JSOI2014」矩形并的更多相关文章

  1. 「JSOI2014」打兔子

    「JSOI2014」打兔子 传送门 首先要特判 \(k \ge \lceil \frac{n}{2} \rceil\) 的情况,因为此时显然可以消灭所有的兔子,也就是再环上隔一个点打一枪. 但是我们又 ...

  2. 「JSOI2014」电信网络

    「JSOI2014」电信网络 传送门 一个点选了就必须选若干个点,最大化点权之和,显然最大权闭合子图问题. 一个点向它范围内所有点连边,直接跑最大权闭合子图即可. 参考代码: #include < ...

  3. 「JSOI2014」学生选课

    「JSOI2014」学生选课 传送门 看到这题首先可以二分. 考虑对于当前的 \(mid\) 如何 \(\text{check}\) 我们用 \(f_{i,j}\) 来表示 \(i\) 对 \(j\) ...

  4. 「JSOI2014」歌剧表演

    「JSOI2014」歌剧表演 传送门 没想到吧我半夜切的 这道题应该算是 \(\text{JSOI2014}\) 里面比较简单的吧... 考虑用集合关系来表示分辨关系,具体地说就是我们把所有演员分成若 ...

  5. 「JSOI2014」支线剧情2

    「JSOI2014」支线剧情2 传送门 不难发现原图是一个以 \(1\) 为根的有根树,所以我们考虑树形 \(\text{DP}\). 设 \(f_i\) 表示暴力地走完以 \(i\) 为根的子树的最 ...

  6. 「JSOI2014」强连通图

    「JSOI2014」强连通图 传送门 第一问很显然就是最大的强连通分量的大小. 对于第二问,我们先把原图进行缩点,得到 \(\text{DAG}\) 后,统计出入度为零的点的个数和出度为零的点的个数, ...

  7. 「JSOI2014」序列维护

    「JSOI2014」序列维护 传送门 其实这题就是luogu的模板线段树2,之所以要发题解就是因为学到了一种比较NB的 \(\text{update}\) 的方式.(参见这题) 我们可以把修改操作统一 ...

  8. 「AHOI2014/JSOI2014」拼图

    「AHOI2014/JSOI2014」拼图 传送门 看到 \(n \times m \le 10^5\) ,考虑根号分治. 对于 \(n < m\) 的情况,我们可以枚举最终矩形的上下边界 \( ...

  9. 「AHOI2014/JSOI2014」宅男计划

    「AHOI2014/JSOI2014」宅男计划 传送门 我们首先要发现一个性质:存货天数随买食物的次数的变化类似于单峰函数. 具体证明不会啊,好像是二分加三分来证明?但是没有找到明确的严格证明. 感性 ...

随机推荐

  1. JS高级---案例:贪吃蛇小游戏

    案例:贪吃蛇小游戏 可以玩的小游戏,略复杂,过了2遍,先pass吧 先创建构造函数,再给原型添加方法.分别创建食物,小蛇和游戏对象. 食物,小蛇的横纵坐标,设置最大最小值,运动起来的函数,按上下左右键 ...

  2. lees入门

    安装 1 下载EasyLess插件 2 新建less文件,输入less语句,保存,就会在同级目录下生成同名的css文件 3 在HTML页面导入 <link rel="styleshee ...

  3. Eclipse配置C++11环境详细介绍

    转:https://blog.csdn.net/wgxh05/article/details/54021049 本文记录Eclipse配置C++11开发所有作者遇到的情况,包括跨工程文件编译,内联文件 ...

  4. JSP技术(三)

    JSP指令 指令是JSP语法元素的第一种类型.它们指示JSP转换器如何翻译JSP页面为Servlet.JSP定义了多个指令,但只有page和include最重要.而taglib.tag.attribu ...

  5. 【PAT甲级】1107 Social Clusters (30分)(非递归并查集)

    题意: 输入一个正整数N(<=1000),表示人数,接着输入N行每行包括一个他的爱好数量:和爱好的序号.拥有相同爱好的人们可以默认他们在同一个俱乐部,输出俱乐部的数量并从大到小输出俱乐部的人数( ...

  6. go基础_函数

    函数的基本写法 func add(a int, b int) int { return a + b } 如果2个参数的类型一样,可以简写为 func add(a, b int) int { retur ...

  7. Flutter 开发入门实践

    前言: Flutter 是 Google 推出的跨平台解决方案, 开发语言:Dart 优势: 劣势: 学习推荐: 官方网站:https://flutter.io/ 书籍:<Flutter技术入门 ...

  8. GBK与Unicode的转换

    一.GBK转换到Unicode编码 std::string Gbk2Unicode(std::string &strValue) { std::string strReturn; unsign ...

  9. Anaconda"无法定位程序输入点 OPENSSL_sk_new_reserve 于动态链接库Anaconda3\Library\bin\libssl-1_1-x64.dll上"的解决办法

    Anaconda"无法定位程序输入点 OPENSSL_sk_new_reserve 于动态链接库Anaconda3\Library\bin\libssl-1_1-x64.dll上" ...

  10. [Fiddler学习] - Mock的简单实现原理及方法

    最近在研究Fidder抓包并做一点测试工作,下面介绍一下Fiddler的实现原理: 简单来说从clent,server端发出来的请求,都需要通过Fiddler进行代理走一遍.如果有任何请求需要做修改, ...