zoukankan      html  css  js  c++  java
  • [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
    ", (x2 - x1 + 1) * res2 + (y2 - y1 + 1) * res1 - res1 * res2 * 2);
            }
        }
        return 0;
    }
  • 相关阅读:
    hdu 1028 Ignatius and the Princess III
    程序猿编程之路
    编程心得
    HDU 1106 排序
    水利水电工程施工导截流方案辅助设计系统成功进行国家计算机软件著作权登记!
    调洪演算双辅助线法计算程序(带石门坎水电站算例)
    水利水电工程施工导截流方案辅助设计系统DivClose——关键技术
    水利水电工程施工导截流方案辅助设计系统DivClose的图形用户界面
    水利水电工程施工导截流方案辅助设计系统DivClose软件特色
    施工导截流方案设计软件现状
  • 原文地址:https://www.cnblogs.com/BriMon/p/9609642.html
Copyright © 2011-2022 走看看