zoukankan      html  css  js  c++  java
  • luogu3801 红色的幻想乡

    题目大意

      给一个初始值都是0的0-1矩阵,两个操作:1.选择一个点,将其所在排和列(不包括该点)的数字取反。2.求一个子矩形内的数字和。n,m,q<=100000.

    错误思路

    为何不能用二维线段树

    1. n,m<=100000,每个x线段树都维护一个有400000个节点的Y线段树,而X节点也要400000个,空间受不了。
    2. 如果我们要更新一排,X线段树没有达到“排除一半”的功能,必须遍历到所有X、Y节点,时间受不了。

    假命题:将所在排列其它数字取反,等价于把选择的点的数字取反

      与后者等价的,是把整个矩阵的其它数字都取反,而不仅仅是其所在排列的。

    正确题解

      不要被“不包括该点”迷惑。翻转不包括该点,相当于先翻转该点所在排,再翻转所在列,该点翻转了两次,数字仍然不变。

      这样,我们就可以从对排和对列单独分析作为思路了。我们可以对于各排和各列定义一个0-1状态表示如果不存在交叉点,则该排上的所有数字是1还是0。定义一排(列)的状态为1,且经过一个矩形,则该排(列)穿过该矩形。这样,我们要查询的子矩形内的数字和就等于穿过该矩形的排数*该矩形占的列数+穿过该矩形的列数*该矩形占的排数-交叉点个数*2(其=穿过该矩形的排数*穿过该矩形的列数)。穿过矩形的排数、列数可以分别对排、列维护一个单点修改,区间查询的线段树表示区间[l,r]内状态为1的点的个数是多少。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    using namespace std;
    
    #define ll long long
    
    const int MAX_NODE = 100010 * 4;
    
    struct RangeTree
    {
    private:
        int Sum[MAX_NODE];
        int N;
        
        void Update(int cur, int l, int r, int p)
        {
            if(l == r)
            {
                assert(p == r && p == l);
                assert(Sum[cur] < 2);
                Sum[cur] = !Sum[cur];
                return;
            }
            int mid = (l + r) / 2;
            if(p <= mid)
                Update(cur * 2, l, mid, p);
            if(p > mid)
                Update(cur * 2 + 1, mid + 1, r, p);
            Sum[cur] = Sum[cur * 2] + Sum[cur * 2 + 1];
        }
        
        ll Query(int cur, int sl, int sr, int al, int ar)
        {
            if(al <= sl && sr <= ar)
                return Sum[cur];
            ll ans = 0;
            int mid = (sl + sr) / 2;
            if(al <= mid)
                ans += Query(cur * 2, sl, mid, al, ar);
            if(ar > mid)
                ans += Query(cur * 2 + 1, mid + 1, sr, al, ar);
            return ans;
        }
        
    public:
        RangeTree(int n):N(n){}
        
        void Update(int p)
        {
            Update(1, 1, N, p);
        }
        
        ll Query(int l, int r)
        {
            return Query(1, 1, N, l, r);
        }
    };
    
    int main()
    {
        int n, m, opCnt;
        scanf("%d%d%d", &n, &m, &opCnt);
        static RangeTree X(n), Y(m);
        while(opCnt--)
        {
            int op, x1, x2, y1, y2;
            ll xCnt, yCnt, totX, totY;
            scanf("%d", &op);
            switch(op)
            {
            case 1:
                scanf("%d%d", &x1, &y1);
                X.Update(x1);
                Y.Update(y1);
                break;
            case 2:
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                xCnt = X.Query(x1, x2);
                yCnt = Y.Query(y1, y2);
                //totX = X.Query(1, n);
                //totY = Y.Query(1, m);
                printf("%lld
    ", xCnt * (y2 - y1 + 1) + yCnt * (x2 - x1 + 1) - xCnt * yCnt * 2);
                break;
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    [css]浮动造成的影响
    [py]django的manytomany字段和后台搜索过滤功能
    [py][lc]python高阶函数(匿名/map/reduce/sorted)
    [py][lc]python的纸牌知识点
    [js]js中类的继承
    [js]js杂项陆续补充中...
    [js]js设计模式小结
    WP10的一点小问题
    JS 判断滚动底部并加载更多效果。。。。。。。。。
    This assembly may have been downloaded from the Web. ......
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9206375.html
Copyright © 2011-2022 走看看