【问题描述】
有一个美丽的童话:在天空的尽头有一个"糖果国",这里大到摩天大厦,小到小花小草都是用糖果建造而成的。更加神奇的是,天空中飘满了五颜六色的糖果云,很快糖果雨密密麻麻从天而落,红色的是草莓糖,黄色的是柠檬糖,绿色的是薄荷糖,黑色的是巧克力糖......这时糖果国的小朋友们便会拿出大大小小的口袋来接天空中落下的糖果,拿回去与朋友们一起分享。
对糖果情有独钟的小 Z 憧憬着能够来到这样一个童话的国度。所谓日有所思,夜有所梦,这天晚上小 Z 梦见自己来到了"糖果国"。他惊喜地发现,任何时候天空中所有的云朵颜色都不相同,不同颜色的云朵在不断地落下相应颜色的糖果。
更加有趣的是所有的云朵都在做着匀速往返运动,不妨想象天空是有边界的,而所有的云朵恰好在两个边界之间做着往返运动。
每一个单位时间云朵向左或向右运动一个单位,当云朵的左界碰到天空的左界,它会改变方向向右运动;当云朵完全移出了天空的右界,它会改变方向向左运动。
我们不妨把天空想象为一个平面直角坐标系,而云朵则抽象为线段(线段可能退化为点):

如上图,不妨设天空的左界为 0,右界为 len。图中共有 5 片云朵,其中标号为 1 的云朵恰好改变方向向右运动,标号为 2 的云朵恰好改变方向向左运动。
忽略云朵的纵坐标,它们在运动过程中不会相互影响。
小 Z 发现天空中会不断出现一些云朵(某个时刻从某个初始位置开始朝某个方向运动),而有的云朵运动到一定时刻就会从天空中消失,而在运动的过程中
糖果在不断地下落。小 Z 决定拿很多口袋来接糖果,口袋容量是无限的,但袋口大小却是有限的。例如在时刻 T 小 Z 拿一个横坐标范围为[L, R]的口袋来接糖果,如果[L, R]存在一个位置 x,该位置有某种颜色的糖果落下,则认为该口袋可接到此种颜色的糖果。极端情况下,袋口区间可能是一个点,譬如[0,0]、[1,1],但仍然可以接到相应位置的糖果。通常可以接到的糖果总数会很大,因而小 Z想知道每一次(即拿出口袋的一瞬间)他的口袋可以接到多少种不同颜色的糖果。
糖果下落的时间忽略不计。
【输入格式】
输入文件 candy.in 的第一行有两个正整数 n, len,分别表示事件总数以及天空的“边界”。
接下来 n 行每行描述一个事件,所有的事件按照输入顺序依次发生。
每行的第一个数 k(k = 1,2,3)分别表示事件的类型,分别对应三种事件:插入事件,询问事件以及删除事件。输入格式如下:

【输出格式】
对于每一个询问事件,输出文件 candy.out 中应包含相应的一行,为该次询问的答案,即口袋可以接到多少种不同的糖果。
【输入样例】
10 10
1 0 10 1 3 -1
2 1 0 0
2 11 0 10
2 11 0 9
1 11 13 4 7 1
2 13 9 9
2 13 10 10
3 100 13
3 1999999999 10
1 2000000000 10 0 1 1
【输出样例】
1
1
0
2
1
【样例说明】
共 10 个事件,包括 3 个插入事件,5 个询问事件以及 2 个删除事件。
时刻 0,天空中出现一片颜色为 10 的云朵,初始位置为[1, 3],方向向左。
时刻 1,范围为[0, 0]的口袋可以接到颜色为 10 的糖果(云朵位置为[0, 2])。
时刻 11,范围为[0,10]的口袋可以接到颜色为 10 的糖果(云朵位置为[10, 12])。
时刻 11,范围为[0, 9]的口袋不能接到颜色为 10 的糖果(云朵位置为[10, 12])。
时刻 11,天空中出现一片颜色为 13 的云朵, 初始位置为[4, 7], 方向向右。
时刻 13,范围为[9, 9]的口袋可以接到颜色为 10(云朵的位置为[8, 10])和颜色为 13(云朵的位置为[6, 9])两种不同的糖果。
时刻 13,范围为[10, 10]的口袋仅仅可以接到颜色为 10 的一种糖果(云朵的位置为[8, 10]),而不可以接到颜色为 13 的糖果(云朵的位置为[6, 9]),。
时刻 100, 颜色为 13 的云朵从天空中消失。
时刻 1999999999,颜色为 10 的云朵从天空中消失。
时刻 2000000000,天空中又出现一片颜色为 10 的云朵,初始位置为[0, 1],方向向右。
【数据规模和约定】
对于所有的数据,0 ≤ Ti ≤ 2000000000,1 ≤ Ci ≤ 1000000。
数据保证{Ti}为非递减序列即 T1 ≤ T2 ≤ ... ≤ Tn-1 ≤ Tn。
对于所有的插入事件,令 Pi = Ri – Li,即 Pi 表示每片云朵的长度。

由于2len是一个周期,先将所有点的初始状态统一,即把云朵(t, L, R, d)变为((t - 2L) % 2len, 0, R - L, 1),这样就可以通过云朵的插入时间和长度来确定每一个云朵了。
询问的时候,就以t = 0为例,可以发现询问的区域是一个很奇怪的区域

(图中的深色部分),但是通过补形,可以将这个奇怪的区域补成一个平行四边形(并且保证填补的部分都是不合法的(即永远也不会计算进去))。再通过简单的坐标变换,可以将图中的平行四边形变成矩形,于是树状数组就派上用场了……
左边的那个平行四边形,可以将坐标(x, y)转化为(x, x + y);右边那个平行四边形,可以将坐标(x, y)转化为(x, y - x),当然不能为负,需要平移纵坐标。
还有,随着时间t的增大,整个平行四边形会向右平移,(并且有可能由于取余的原因,将平行四边形拆成两半。)所以插入的时候要将插入到多个地方。
另外,R = 0时,左右两边的平行四边形所对应的区域重合,所以此时不需要计算右边的平行四边形;R = len时,左右两边平行四边形的两边界都重合,所以计算右边四边形的时候将左界加一。
代码:

/***************************\* @prob: NOI2008 candy    ** @auth: Wang Junji       ** @stat: Accepted.        ** @date: May. 25th, 2012  ** @memo: 树状数组          *
\***************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>const int maxN = 1010, maxC = 1000010;
typedef int arr[maxN * 3][maxN << 2];
struct Cloud {int t, p;} cloud[maxC];
arr a, b; int n, m, len, T;inline void Add(arr a, int x0, int y0, int d)
{for (int i = x0 + 1; i < len * 3 + 2; i += i & -i)for (int j = y0 + 1; j < (len << 2) + 1; j += j & -j)a[i][j] += d;return;
}inline int area(arr a, int x0, int y0)
{int ans = 0;for (int i = x0 + 1; i; i -= i & -i)for (int j = y0 + 1; j; j -= j & -j)ans += a[i][j];return ans;
}inline void Add_a(int x, int y, int d) {Add(a, x, x + y, d); return;}
inline void Add_b(int x, int y, int d) {Add(b, x - len, y - x + m, d); return;}inline int area_a(int x0, int y0, int x1, int y1)
{return area(a, x1, x1 + y1) - area(a, x0 - 1, x1 + y1)- area(a, x1, x0 + y0 - 1) + area(a, x0 - 1, x0 + y0 - 1);
}inline int area_b(int x0, int y0, int x1, int y1)
{return area(b, x1 - len, y1 - x1 + m)- area(b, x0 - len - 1, y1 - x1 + m)- area(b, x1 - len, y0 - x0 + m - 1)+ area(b, x0 - len - 1, y0 - x0 + m - 1);
}inline void adjust(int c, int d)
{int t = cloud[c].t, p = cloud[c].p;Add_a(t, p, d); if (t <= len) Add_a(t + n, p, d);//插入到左边时,进行平移处理。Add_b(t + n, p, d); if (t >= len) Add_b(t, p, d);//插入到右边时,进行平移处理。return;
}inline int ask(int t, int L, int R)
{int ans = area_a(t, L, t + R, len), d = len == R; if (!R) return ans;return ans += area_b(t + n - R + d, L - R + d, t + n - 1, len + R - 1);//算右边平行四边形的时候右边界减一,//因为右边界已经在左边的平行四边形中计算过一遍,不必重新计算。
}int main()
{freopen("candy.in", "r", stdin);freopen("candy.out", "w", stdout);scanf("%d%d", &T, &len); n = len << 1, m = n << 1;while (T--){int K, t, c, L, R, d; scanf("%d%d", &K, &t); t %= n;switch (K){case 1:scanf("%d%d%d%d", &c, &L, &R, &d);cloud[c].t = (t - d * L + n) % n;cloud[c].p = R - L;adjust(c, 1); break;case 2:scanf("%d%d", &L, &R);printf("%d\n", ask(t, L, R));break;case 3: scanf("%d", &c); adjust(c, -1); break;}}return 0;
}

★【树状数组】【NOI2008】糖果雨相关推荐

  1. 【BZOJ1062】糖果雨(NOI2008)-数形结合+二维树状数组

    测试地址:糖果雨 做法:本题需要用到数形结合+二维树状数组. 这题看上去非常没有思路,因此我们来一步一步整理一下思路. 首先,我们要发现线段的颜色互不相同,并且移动的速度相等,这就说明它们的运动是周期 ...

  2. 【BZOJ 1062】 1062: [NOI2008]糖果雨 (二维树状数组)**

    1062: [NOI2008]糖果雨 Description 有一个美丽的童话:在天空的尽头有一个" 糖果国" ,这里大到摩天大厦,小到小花小草都是用糖果建造而成 的.更加神奇的是 ...

  3. Bzoj 4548: 小奇的糖果(双向链表+排序+树状数组)

    以下内容来自ShallWe's Blog 题目 4548: 小奇的糖果 Description 有\(N\)个彩色糖果在平面上.小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果.求出最多能 ...

  4. bzoj 4548: 小奇的糖果 bzoj 3658: Jabberwocky(双向链表+树状数组)

    3658: Jabberwocky Time Limit: 20 Sec  Memory Limit: 1024 MB Submit: 263  Solved: 107 [Submit][Status ...

  5. [NOI2008]糖果雨

    bzoj1062[Noi2008]糖果雨 首先给出的颜色没有用. 估计要用数据结构.而线段难以维护. 考虑把线段变成点 T是单增的. 所以询问的时候,存在的线段都可能贡献答案. 那些线段的位置如果可以 ...

  6. 【2018.12.15】【考试总结】【模拟+逆序对+树状数组+贪心+multiset】爆零之旅

    这是我悲惨的接近爆零的一次考试,但是本蒟蒻不能放弃,还是要总结的QAQ 答题卡 [题目背景] 八月是个悲惨的月份.先不谈炎热的天气,对于新生来说,八月意味着军训: 而对于高二高三的同学来说,八月意味着 ...

  7. 数据结构 【树状数组】【线段树】【珂朵莉树】

    一.区间合并 1.AcWing245你能回答这些问题吗 分析: 线段树.维护四个变量,即可实现区间合并. mx 区间最大连续子段和 mx_l 以区间左端点为左界的最大连续字段和 mx_r 以区间左端点 ...

  8. [NOI2008]糖果雨——数形结合的思想

    题目描述: 维护一个线段集合支持以下操作: 1. add T L R D :在T秒时加入一条L至R的线段,运动方向为D(每秒向右移动D个单位),D为1或-1. 2. ask t L R: 询问t时刻有 ...

  9. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

最新文章

  1. 自学python需要安装什么软件-学Python需要安装什么软件?Python软件工具大全
  2. 解决前端页面闪烁问题(转载)
  3. (原創) 如何讓P7010外接螢幕支援1440x900(WXGA+)? (NB) (P7010)
  4. react 中子组件调用父组件的方法
  5. Special Judge Ⅲ(这道题考的就是出栈序列判定_关键代码不差什么)
  6. ResultSet 结果集
  7. 2015北京网络赛 G题 Boxes bfs
  8. h5页面 pc端html 调用QQ群
  9. 数据结构(三)之单链表反向查找
  10. 如何在Tomcat中设置JNDI数据库连接池-Spring教程示例
  11. 程序员必看!Android面试10大知识点总结宝典助你通关!年薪50W
  12. [bzoj1925][Sdoi2010]地精部落
  13. base64和hex
  14. Java read failed_android-获取java.io.IOException:读取失败,套接...
  15. MVC采用Jquery实现局部刷新
  16. 监测生命体征、活动水平的可穿戴电子产品设计方案
  17. WIZ ConfigTool-批量配置WIZnet S2E模块
  18. Mysql 导入3亿数据
  19. 4.24 使用形状生成器工具绘制星形图标 [Illustrator CC教程]
  20. 微信小程序社群管理解决方案

热门文章

  1. Word2016写论文之——常用操作总结
  2. Verilog语言注意事项
  3. java 获取est时间_java – 在EST时区获取XMLGregorianCalendar日期
  4. 亚马逊AWS EC212个月免费计划及连接问题
  5. 兔子与狐狸c语言,狐狸和兔子
  6. php 微信定位源码_微信活码模块源码 - WEB源码|PHP源码|源代码 - 源码中国
  7. 黑客大神用什么杀毒? Windows 自带的就够, 只是加了亿点微小的强化
  8. 介绍一个用于EOS区块链的RPC API接口的PHP开发包SDK
  9. 大屏可视化色彩设计基本知识
  10. IEEE 754二进制浮点数算术标准