1. 程式人生 > 其它 >AtCoder Beginner Contest 253 F - Operations on a Matrix // 樹狀陣列

AtCoder Beginner Contest 253 F - Operations on a Matrix // 樹狀陣列

題目傳送門:F - Operations on a Matrix (atcoder.jp)

題意:

給一個N*M大小的零矩陣,以及Q次操作。操作1(l,r,x):對於 [l,r] 區間內的每列都加上x;操作2(i,x):對於第 i 行,替換為x;操作3(i,j):查詢矩陣第 i 行,第 j 列元素的值。

N、M、Q大小均為2E5.

 

思路:樹狀陣列

首先考慮沒有操作2的情況,那麼很容易地就可以用樹狀陣列實現對列的區間加及單點查詢。

當有操作2時,對於操作3的查詢:將該行最後一次操作2的行修改值記作x,從最後一次操作2到該次操作所有的1操作列增加值記作sum2,那麼輸出的答案就為x + sum2。將從開始到該次操作的所有1操作列增加值記作sum,從開始到最後一次操作2的列增加值記作sum1,那麼有sum2 = sum - sum1,答案就為:x + sum - sum1。離線查詢即可。

 

程式碼參考:

#include <bits/stdc++.h>
#define LL long long
#define lowbit(x) (x & -x)
using namespace std;

const int N = 200010;

int n, m, Q, last[N];
LL tr[N], ans[N];
vector<int> v[N];

struct query {
    int op, a, b, c;
} q[N];

void add(int x, int c)
{
    for(int i = x; i <= m; i += lowbit(i)) tr[i] += c;
}

LL sum(
int x) { LL res = 0; for(int i = x; i; i -= lowbit(i)) res += tr[i]; return res; } int main() { cin >> n >> m >> Q; for(int i = 1; i <= Q; i++) { scanf("%d%d%d", &q[i].op, &q[i].a, &q[i].b); if(q[i].op == 1) scanf("%d", &q[i].c);
else if(q[i].op == 2) last[q[i].a] = i; else v[last[q[i].a]].push_back(i); } for(int i = 1; i <= Q; i++) { if(q[i].op == 1) add(q[i].a, q[i].c), add(q[i].b + 1, -q[i].c); else if(q[i].op == 2) for(auto item : v[i]) ans[item] = q[i].b - sum(q[item].b); else printf("%lld\n", ans[i] + sum(q[i].b)); } return 0; }