[ABC253F] Operations on a Matrix 题解

[ABC253F] Operations on a Matrix Solution

更好的阅读体验戳此进入

题面

存在 $ n $ 行 $ m $ 列的矩阵,给定 $ q $ 次操作,有 $ 3 $ 种格式。

  • 1 l r x:将 $ [l, r] $ 列的所有元素全部加上 $ x $。
  • 2 i x:将第 $ i $ 行的元素全部变为 $ x $。
  • 3 i j:输出矩阵 $ (i, j) $ 位置的元素值。

Solution

感觉还算是一道细节不少的题。

首先这道题的做法不少,主流的就是类似二位偏序维护,或者写一个区间修改的主席树。

这里主要说一下用 BIT 维护的方法。

首先不难想到,$ 2 $ 操作会覆盖掉前面所有的对其有影响的 $ 1 $ 操作。然后 $ 1 $ 操作是区间修改列,$ 2 $ 操作是单点推平行。所以考虑离线,然后对于每个查询,令其序号为 $ r $,有行 $ x $ 列 $ y $,我们要找到在其之前的上一个推平 $ x $ 行,令其的操作序号为 $ l $,那么我们就需要对这个答案初始设为那次推平的值,然后加上 $ [l, r] $ 之间的所有的对于 $ y $ 列的操作。

思路就是这样,维护的方式还是有些高妙的。先考虑离线一遍,然后维护对于每个查询的上一次对应的推平,同时维护该查询的初始值,然后在需要减去的位置开个 basic_string 插进去需要减的序号。然后我们考虑会有一次区间的查询,用 BIT 和前缀和维护,再遍历一次操作,先将前缀加起来,然后减去的那个前缀就在我们第二次遍历的时候通过遍历对应的 basic_string 而减去。然后最后跑一遍输出答案即可。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N, M, Q;
int lst[210000], pos[210000];
ll ans[210000];
struct Query{int opt; int a, b, c;}qs[210000];
basic_string < int > del[210000];

class BIT{
private:
    ll tr[210000];
public:
    int lowbit(int x){return x & -x;}
    void Modify(int x, int v){while(x <= M)tr[x] += v, x += lowbit(x);}
    ll Query(int x){ll ret(0); while(x)ret += tr[x], x -= lowbit(x); return ret;}
    void ModifyRange(int l, int r, ll v){Modify(l, v), Modify(r + 1, -v);}
}bit;

int main(){
    // freopen("test_05.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    N = read(), M = read(), Q = read();
    for(int i = 1; i <= Q; ++i){
        int opt = read();
        switch(opt){
            case 1:{
                int l = read(), r = read(), v = read(); qs[i] = Query{opt, l, r, v};
                break;
            }
            case 2:{
                int p = read(), v = read(); qs[i] = Query{opt, p, v};
                pos[p] = i;
                break;
            }
            case 3:{
                int x = read(), y = read(); qs[i] = Query{opt, x, y};
                ans[i] = qs[pos[x]].b;
                del[pos[x]] += i;
                break;
            }
            default: break;
        }
    }
    for(int i = 1; i <= Q; ++i){
        switch(qs[i].opt){
            case 1:{bit.ModifyRange(qs[i].a, qs[i].b, qs[i].c); break;}
            case 2:{for(auto p : del[i])ans[p] -= bit.Query(qs[p].b); break;}
            case 3:{ans[i] += bit.Query(qs[i].b); break;}
            default: break;
        }
    }
    for(int i = 1; i <= Q; ++i)if(qs[i].opt == 3)printf("%lld\n", ans[i]);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_12_05 初稿

posted @ 2023-01-07 15:31  Tsawke  阅读(48)  评论(0)    收藏  举报