[Luogu3801] 红色的幻想乡

题目背景

蕾米莉亚的红雾异变失败后,很不甘心。

题目描述

经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放。

我们将幻想乡看做是一个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,输出一行一个整数,表示对应询问的答案。

输入输出样例

输入样例#1: 复制
4 4 3
1 2 2
1 4 4
2 1 1 4 4
输出样例#1: 复制
8

说明

样例解释:

用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\n", (x2 - x1 + 1) * res2 + (y2 - y1 + 1) * res1 - res1 * res2 * 2);
        }
    }
    return 0;
}

 

 

 

posted @ 2018-09-08 16:52  zZhBr  阅读(188)  评论(0编辑  收藏  举报