zoukankan      html  css  js  c++  java
  • LG7881 [Ynoi2006] rmpq【分块,分治】

    这是一道交互题

    维护 \(10^9\times 10^9\) 的二维数组,元素属于含幺半群 \(D\),初始时均为单位元 \(e\)\(n\) 次操作:

    • 给定一条水平或竖直的直线将数组分成两部分,再给定 \(d_1,d_2\in D\),两部分分别右乘 \(d_1,d_2\)
    • 单点查询。

    \(n\le 10^5\)\(D\) 上的乘法只能进行 \(2\cdot 10^7\) 次。


    因为乘法没有交换律,所以只能按照时间顺序依次处理,又因为强制在线,所以考虑按时间分块(根号重构),对每 \(B\) 次修改计算出 \(B^2\) 个区域的值,查询的时候定位到区域的值然后乘起来即可。

    现在考虑怎么计算,暴力做法是 \(O(B^3)\) 的,但是若修改都在查询前就可以分治做到 \(O(B^2)\),然后用二进制分组替代这个分治就可以同时修改和查询。空间复杂度 \(O(nB)\),时间复杂度 \(O(nB+n^2/B)\)

    #include<bits/stdc++.h>
    #define PB emplace_back
    using namespace std;
    const int N = 256, INF = 1.5e9;
    struct Data {
        unsigned short a, b, c, d;
        void operator *= (const Data &x);
        void clr();
    };
    Data operator * (Data a, const Data &b){a *= b; return a;}
    struct Node {
        int n1, n2, *v1, *v2;
        Data *val;
        int siz(){return max(0, n1 + n2 - 2);}
        void init(int _1, int _2){
            v1 = new int [n1 = _1];
            v2 = new int [n2 = _2];
            val = new Data [n1 * n2];
        }
        void init(int x, int op, const Data &d1, const Data &d2){
            if(op){init(1, 2); v2[0] = x; v1[0] = v2[1] = INF;}
            else {init(2, 1); v1[0] = x; v1[1] = v2[0] = INF;}
            val[0] = d1; val[1] = d2;
        }
        Node operator + (const Node &o) const {
            static int p1[N], p2[N], q1[N], q2[N];
            Node res; res.init(n1 + o.n1 - 1, n2 + o.n2 - 1);
            for(int i = 0, j = 0;i < n1;++ i){
                while(j < o.n1 && o.v1[j] < v1[i]){
                    p1[i+j] = i; p2[i+j] = j; res.v1[i+j] = o.v1[j]; ++ j;
                }
                p1[i+j] = i; p2[i+j] = j; res.v1[i+j] = v1[i];
            }
            for(int i = 0, j = 0;i < n2;++ i){
                while(j < o.n2 && o.v2[j] < v2[i]){
                    q1[i+j] = i; q2[i+j] = j; res.v2[i+j] = o.v2[j]; ++ j;
                }
                q1[i+j] = i; q2[i+j] = j; res.v2[i+j] = v2[i];
            }
            for(int i = 0;i < res.n1;++ i)
                for(int j = 0;j < res.n2;++ j)
                    res.val[i*res.n2+j] = val[p1[i]*n2+q1[j]] * o.val[p2[i]*o.n2+q2[j]];
            return res;
        }
        Data qry(int x, int y){
            return val[(upper_bound(v1, v1+n1, x) - v1) * n2 + (upper_bound(v2, v2+n2, y) - v2)];
        }
    } st[512];
    int tp;
    void update(int x, int dim, Data d1, Data d2){
        st[++tp].init(x, dim, d1, d2);
        while(tp > 1 && st[tp-1].siz() <= st[tp].siz() && st[tp].siz() < N)
            st[tp-1] = st[tp-1] + st[tp], -- tp;
    }
    Data query(int x, int y){
        Data res; res.clr();
        for(int i = 1;i <= tp;++ i) res *= st[i].qry(x, y);
        return res;
    }
    
  • 相关阅读:
    Android 按键消息处理Android 按键消息处理
    objcopy
    SQLite多线程读写实践及常见问题总结
    android动画坐标定义
    Android动画效果translate、scale、alpha、rotate
    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)
    Flatten Binary Tree to Linked List
    Distinct Subsequences
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/15696915.html
Copyright © 2011-2022 走看看