題意:
給你n個細胞, 分別爲1到n, 執行兩種操作
1 查詢l, r區間同一種細胞的最大數目
2 更新:將l, r區間的細胞複製一遍
分析:
區間更新和區間查詢明顯是線段樹的題目, 比賽的時候卻因爲區間長度會變化而不知道怎麼做了, 其實同一種細胞總是相鄰的, 所以可以根據查詢的區間求得細胞的類型範圍
對於更新操作, 對類型的兩個端點進行單點更新,中間進行成段更新
對於查詢操作, 分別求兩個端點的長度和中間的長度, 去最大值即可
#include
#include
#include
using namespace std;
typedef long long ll;
ll maxn[50010 << 2], sum[50010 << 2], lazy[50010 << 2];
ll lx, rx, k;
int n, m, x, ql, qr;
void pushUp(int o) {
maxn[o] = max(maxn[2 * o], maxn[2 * o + 1]);
sum[o] = sum[2 * o] + sum[2 * o + 1];
}
void pushDown(int o) {
lazy[2 * o] += lazy[o];
lazy[2 * o + 1] += lazy[o];
sum[2 * o] <<= lazy[o];
sum[2 * o + 1] <<= lazy[o];
maxn[2 * o] <<= lazy[o];
maxn[2 * o + 1] <<= lazy[o];
lazy[o] = 0;
}
void construct(int o, int l, int r) {
lazy[o] = 0;
if (l == r) {
maxn[o] = sum[o] = 1;
return;
}
int m = (l + r) >> 1;
construct(2 * o, l, m);
construct(2 * o + 1, m + 1, r);
pushUp(o);
}
int getId(int o, int l, int r, ll x) {
if (l == r) return l;
if (lazy[o]) pushDown(o);
int m = (l + r) >> 1;
if (sum[2 * o] >= x) {
return getId(2 * o, l, m, x);
}
else {
x -= sum[2 * o];
return getId(2 * o + 1, m + 1, r, x);
}
}
void update1(int o, int l, int r) {
if (l == r) {
sum[o] += k;
maxn[o] += k;
return;
}
if (lazy[o]) pushDown(o);
int m = (l + r) >> 1;
if (x <= m) update1(2 * o, l, m);
else update1(2 * o + 1, m + 1, r);
pushUp(o);
}
void update2(int o, int l, int r) {
if (ql <= l && qr >= r) {
sum[o] *= 2;
maxn[o] *= 2;
lazy[o] ++;
return;
}
if (lazy[o]) pushDown(o);
int m = (l + r) >> 1;
if (ql <= m) update2(2 * o, l, m);
if (qr > m) update2(2 * o + 1, m + 1, r);
pushUp(o);
}
ll querySum(int o, int l, int r) {
if (ql <= l && qr >= r) return sum[o];
ll ans = 0;
if (lazy[o]) pushDown(o);
int m = (l + r) >> 1;
if (ql <= m) ans += querySum(2 * o, l, m);
if (qr > m) ans += querySum(2 * o + 1, m + 1, r);
return ans;
}
ll query(int o, int l, int r) {
if (ql <= l && qr >= r) return maxn[o];
if (lazy[o]) pushDown(o);
int m = (l + r) >> 1;
ll ans = 0;
if (ql <= m) ans = max(ans, query(2 * o, l, m));
if (qr > m) ans = max(ans, query(2 * o + 1, m + 1, r));
return ans;
}
int main() {
int T, ca = 1;
scanf("%d", &T);
while (T --) {
scanf("%d%d", &n, &m);
construct(1, 1, n);
printf("Case #%d:\n", ca++);
while (m --) {
char s[10];
scanf("%s%I64d%I64d", s, &lx, &rx);
int id1 = getId(1, 1, n, lx);
int id2 = getId(1, 1, n, rx);
if (s[0] == 'D') {
if (id1 == id2) {
x = id1;
k = rx - lx + 1;
update1(1, 1, n);
}
else {
ql = 1, qr = id2 - 1;
x = id2;
k = rx - querySum(1, 1, n);
update1(1, 1, n);
ql = 1, qr = id1;
x = id1;
k = querySum(1, 1, n) - lx + 1;
update1(1, 1, n);
ql = id1 + 1, qr = id2 - 1;
if (ql <= qr) update2(1, 1, n);
}
}
else {
if (id1 == id2) {
printf("%I64d\n", rx - lx + 1);
}
else {
ll res = 0;
ql = 1, qr = id2 - 1;
res = max(res, rx - querySum(1, 1, n));
ql = 1, qr = id1;
res = max(res, querySum(1, 1, n) - lx + 1);
ql = id1 + 1, qr = id2 - 1;
if (ql <= qr) res = max(res, query(1, 1, n));
printf("%I64d\n", res);
}
}
}
}
return 0;
}