题目背景
蕾米莉亚的红雾异变失败后,很不甘心。
题目描述
经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放。
我们将幻想乡看做是一个n*m的方格地区,一开始没有任何一个地区被红雾遮盖。蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行/整列,但不会影响到她所站的那个地区。如果两阵红雾碰撞,则会因为密度过大而沉降消失。灵梦察觉到了这次异变,决定去解决它。但在解决之前,灵梦想要了解一片范围红雾的密度。可以简述为两种操作:
1 x y 蕾米莉亚站在坐标(x,y)的位置向四个方向释放无限长的红雾。
2 x1 y1 x2 y2 询问左上点为(x1,y1),右下点为(x2,y2)的矩形范围内,被红雾遮盖的地区的数量。
输入输出格式
输入格式:第一行三个整数n,m,q,表示幻想乡大小为n*m,有q个询问。
接下来q行,每行3个或5个整数,用空格隔开,含义见题目描述。
输出格式:对于每一个操作2,输出一行一个整数,表示对应询问的答案。
输入输出样例
说明
样例解释:
用o表示没有红雾,x表示有红雾,两次释放红雾后幻想乡地图如下:
oxox
xoxo
oxox
xoxo
数据范围:
对于20%的数据,1<=n,m,q<=200
对于 40%的数据,1<=n,m,q<=1000
对于100%的数据,1<=n,m,q<=100000
1<=x1,x2,x<=n x1<=x2
1<=y1,y2,y<=m y1<=y2
by-orangebird
题目中唯一一个看起来不太舒服的就是起点不被覆盖, 但是想想其实起点是因为行和列都有覆盖所以它没有。
于是不用单独考虑起点的问题了。
所以我们开两个线段树,分别维护行和列是否被覆盖。
如果给定的区域的行的长度为$L1$, 列的长度为$L2$,行有$res1$个被覆盖, 列有$res2$个被覆盖。
那么答案就是$large L1 * res2 + L2 * res1 - res1 * res2 * 2$。
就是加上行上的个数,加上列上的个数, 然后行和列有交点, 交点都不会对答案产生贡献, 于是减去两倍的$res1*res2$。
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <cmath> using namespace std; #define reg register #define int long long inline int read() { int res = 0;char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar(); return res; } #define N 100005 int n, m, q; int tr1[N<<2], tr2[N<<2]; #define ls(o) o << 1 #define rs(o) o << 1 | 1 void change1(int l, int r, int o, int pos) { if (l == r) {tr1[o] ^= 1;return ;} int mid = l + r >> 1; if (pos <= mid) change1(l, mid, ls(o), pos); else change1(mid + 1, r, rs(o), pos); tr1[o] = tr1[ls(o)] + tr1[rs(o)]; } void change2(int l, int r, int o, int pos) { if (l == r) {tr2[o] ^= 1;return ;} int mid = l + r >> 1; if (pos <= mid) change2(l, mid, ls(o), pos); else change2(mid + 1, r, rs(o), pos); tr2[o] = tr2[ls(o)] + tr2[rs(o)]; } int query1(int l, int r, int o, int ql, int qr) { if (l >= ql and r <= qr) return tr1[o]; int mid = l + r >> 1; int res = 0; if (ql <= mid) res += query1(l, mid, ls(o), ql, qr); if (qr > mid) res += query1(mid + 1, r, rs(o), ql, qr); return res; } int query2(int l, int r, int o, int ql, int qr) { if (l >= ql and r <= qr) return tr2[o]; int mid = l + r >> 1; int res = 0; if (ql <= mid) res += query2(l, mid, ls(o), ql, qr); if (qr > mid) res += query2(mid + 1, r, rs(o), ql, qr); return res; } signed main() { n = read(), m = read(), q = read(); while(q--) { int opt = read(); if (opt == 1) { int x = read(), y = read(); change1(1, n, 1, x), change2(1, n, 1, y); } else { int x1 = read(), y1 = read(), x2 = read(), y2 = read(); int res1 = query1(1, n, 1, x1, x2), res2 = query2(1, n, 1, y1, y2); printf("%lld ", (x2 - x1 + 1) * res2 + (y2 - y1 + 1) * res1 - res1 * res2 * 2); } } return 0; }