题目链接:COGS2651
题目大意
作为知识与历史的半兽,慧音可以更改某个时刻的历史:
t
时刻及以后,区间
询问和修改交错给出,问慧音在进行了前面的操作后,时刻
t
的
分析
1. 我们把妖怪在所有时刻的状态平铺在平面上,初始化全部为初始状态:比如
时刻1 | 时刻2 | 时刻3 | 时刻4 | … | |
---|---|---|---|---|---|
妖怪1 | 1 | 1 | 1 | 1 | … |
妖怪2 | 2 | 2 | 2 | 2 | … |
妖怪3 | 3 | 3 | 3 | 3 | … |
妖怪4 | 4 | 4 | 4 | 4 | … |
… |
2. 然后,修改操作就变成了修改平面上一个矩形的值,比如:
进行操作M 4 4 5 1 2 1 3
时刻1 | 时刻2 | 时刻3 | 时刻4 | … | |
---|---|---|---|---|---|
妖怪1 | 1 | 1 | 2 | 2 | … |
妖怪2 | 2 | 2 | 3 | 3 | … |
妖怪3 | 3 | 3 | 3 | 3 | … |
妖怪4 | 4 | 4 | -1 | -1 | … |
… |
3. 于是就与另一道经典CDQ分治十分相似了:Mokia题解,只不过是把单点修改变成了区间修改,而且修改不用拆分成前后两段,因为这道题的询问只有左界没有右界。
ps. COGS也有Mokia这道题。
UPD: 换了一份代码。
上代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 5e4 + 10;
const int M = 1e5 + 10;
int n, m, t;
inline int read() {
register char ch = getchar();
register int ans = 0, neg = 1;
for (; !isdigit(ch); ch = getchar())
if (ch == '-') neg = -1;
for (; isdigit(ch); ch = getchar())
ans = ans * 10 + ch - '0';
return ans * neg;
}
namespace ST {
const int M = 3e5 + 10;
bool cls[M];
LL val[M], add[M];
#define lc(a) (a << 1)
#define rc(a) (lc(a) | 1)
inline void clearVal(int a) {
cls[a] = true, val[a] = add[a] = 0;
}
inline void addVal(int a, int l, int r, int c) {
add[a] += c, val[a] += (LL)c * (r - l + 1);
}
inline void pushDown(int a, int l, int r) {
if (cls[a]) {
cls[a] = false;
clearVal(lc(a)), clearVal(rc(a));
}
if (add[a]) {
int mid = (l + r) >> 1;
addVal(lc(a), l, mid, add[a]);
addVal(rc(a), mid + 1, r, add[a]);
add[a] = 0;
}
}
void build(int a, int l, int r) {
if (l == r) return val[a] = read(), void(0);
int mid = (l + r) >> 1;
build(lc(a), l, mid), build(rc(a), mid + 1, r);
val[a] = val[lc(a)] + val[rc(a)];
}
void modify(int a, int l, int r, int ll, int rr, int c) {
pushDown(a, l, r);
if (l == ll && r == rr) return addVal(a, l, r, c);
val[a] += (LL)c * (rr - ll + 1);
int mid = (l + r) >> 1;
if (rr <= mid) return modify(lc(a), l, mid, ll, rr, c);
else if (ll > mid) return modify(rc(a), mid + 1, r, ll, rr, c);
return modify(lc(a), l, mid, ll, mid, c), modify(rc(a), mid + 1, r, mid + 1, rr, c);
}
LL query(int a, int l, int r, int ll, int rr) {
pushDown(a, l, r);
if (l == ll && r == rr) return val[a];
int mid = (l + r) >> 1;
if (rr <= mid) return query(lc(a), l, mid, ll, rr);
else if (ll > mid) return query(rc(a), mid + 1, r, ll, rr);
return query(lc(a), l, mid, ll, mid) + query(rc(a), mid + 1, r, mid + 1, rr);
}
}
int cnt, cntAns;
LL ans[N];
struct Op {
int type, l, r, t, c;
LL *plc;
} op[M];
void init() {
n = read(), m = read();
ST::build(1, 1, n);
char ss[5];
for (int i = 1; i <= m; ++i)
if (scanf("%s", ss), *ss == 'Q') {
op[++cnt].type = 0;
op[cnt].l = read(), op[cnt].r = read(), op[cnt].t = read();
op[cnt].plc = &ans[++cntAns];
ans[cntAns] += ST::query(1, 1, n, op[cnt].l, op[cnt].r);
} else {
op[++cnt].type = 1;
op[cnt].l = read(), op[cnt].r = read(), op[cnt].c = -read();
op[++cnt].type = 1;
op[cnt].l = read(), op[cnt].r = read(), op[cnt].c = read();
op[cnt - 1].t = op[cnt].t = read();
}
}
Op ary[M];
void figure(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
figure(l, mid), figure(mid + 1, r);
ST::clearVal(1);
int ll = l, rr = mid + 1, tmp = l - 1;
while (ll <= mid && rr <= r) {
if (op[ll].t <= op[rr].t) {
ary[++tmp] = op[ll++];
if (ary[tmp].type)
ST::modify(1, 1, n, ary[tmp].l, ary[tmp].r, ary[tmp].c);
} else {
ary[++tmp] = op[rr++];
if (!ary[tmp].type)
*ary[tmp].plc += ST::query(1, 1, n, ary[tmp].l, ary[tmp].r);
}
}
while (ll <= mid) {
ary[++tmp] = op[ll++];
if (ary[tmp].type)
ST::modify(1, 1, n, ary[tmp].l, ary[tmp].r, ary[tmp].c);
}
while (rr <= r) {
ary[++tmp] = op[rr++];
if (!ary[tmp].type)
*ary[tmp].plc += ST::query(1, 1, n, ary[tmp].l, ary[tmp].r);
}
for (int i = l; i <= r; ++i) op[i] = ary[i];
}
int main() {
// freopen("cdcq_a.in", "r", stdin);
// freopen("cdcq_a.out", "w", stdout);
init();
figure(1, cnt);
for (int i = 1; i <= cntAns; ++i)
printf("%lld\n", ans[i]);
return 0;
}
以上