题意:
给你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;
}