• 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;
    }
    
  • 相关阅读:
    C#类头部声明样式
    VisualStudio使用技巧及快捷键
    #使用ListView更新数据出现闪烁解决办法
    获取公网IP地址
    JArray数组每个JObject对象添加一个键值对
    部署网站出现System.ServiceModel.Activation.HttpModule错误
    MYSQL存储引擎的比较
    数据库索引原理(转载)
    皮尔逊相关系数
    进程与线程
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/15696915.html
Copyright © 2020-2023  润新知