题意:初始序列 1, 2, ..., n,m次操作(1 <= n,m<= 50000),每次操作可为:
D l r,将区间[l, r]中的所有数复制一次;
Q l r,输出区间[l, r]中同一数字个数的最大值。
(0 <= r – l <= 10^8, 1 <= l, r <= 序列元素个数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4973
——>>因为区间内数字是依次递增的,所以可以以数字为叶建线段树去维护区间同一数字个数最大值。。
原查询区间[l, r],转换成区间[l位对应的数字,r位对应的数字]的线段树查询。。
接着就是SB的线段树操作了。。
注意区间的分段处理。。
#include <cstdio>
#include <algorithm>#define lc (o << 1)
#define rc ((o << 1) | 1)using std::max;const int MAXN = 50000 + 10;int mul[MAXN << 2];
long long sum[MAXN << 2], maxv[MAXN << 2];int ReadInt()
{int ret = 0;char ch;while ((ch = getchar()) && ch >= '0' && ch <= '9'){ret = ret * 10 + ch - '0';}return ret;
}void Pushdown(int o)
{if (mul[o]){mul[lc] += mul[o];mul[rc] += mul[o];sum[lc] <<= mul[o];sum[rc] <<= mul[o];maxv[lc] <<= mul[o];maxv[rc] <<= mul[o];mul[o] = 0;}
}void Maintain(int o)
{sum[o] = sum[lc] + sum[rc];maxv[o] = max(maxv[lc], maxv[rc]);
}void Build(int o, int L, int R)
{mul[o] = 0;if (L == R){sum[o] = 1;maxv[o] = 1;return;}int M = (L + R) >> 1;Build(lc, L, M);Build(rc, M + 1, R);Maintain(o);
}int QueryFigure(int o, int L, int R, long long index)
{if (L == R) return L;Pushdown(o);int M = (L + R) >> 1;return index <= sum[lc] ? QueryFigure(lc, L, M, index) : QueryFigure(rc, M + 1, R, index - sum[lc]);
}long long QuerySum(int o, int L, int R, int ql, int qr)
{if (ql <= L && R <= qr) return sum[o];Pushdown(o);int M = (L + R) >> 1;long long ret = 0;if (ql <= M){ret += QuerySum(lc, L, M, ql, qr);}if (qr > M){ret += QuerySum(rc, M + 1, R, ql, qr);}return ret;
}void UpdateInterval(int o, int L, int R, int ql, int qr)
{if (ql <= L && R <= qr){sum[o] <<= 1;maxv[o] <<= 1;mul[o]++;return;}Pushdown(o);int M = (L + R) >> 1;if (ql <= M){UpdateInterval(lc, L, M, ql, qr);}if (qr > M){UpdateInterval(rc, M + 1, R, ql, qr);}Maintain(o);
}void UpdateLeaf(int o, int L, int R, int q, int add)
{if (L == R){sum[o] += add;maxv[o] += add;return;}Pushdown(o);int M = (L + R) >> 1;if (q <= M){UpdateLeaf(lc, L, M, q, add);}else{UpdateLeaf(rc, M + 1, R, q, add);}Maintain(o);
}void Update(int n, int l, int r, int ql, int qr)
{if (ql == qr){UpdateLeaf(1, 1, n, ql, r - l + 1);}else{int addLeft = QuerySum(1, 1, n, 1, ql) - l + 1;int addRight = r - QuerySum(1, 1, n, 1, qr - 1);UpdateLeaf(1, 1, n, ql, addLeft);UpdateLeaf(1, 1, n, qr, addRight);if (qr - ql >= 2){UpdateInterval(1, 1, n, ql + 1, qr - 1);}}
}long long QueryMax(int o, int L, int R, int ql, int qr)
{if (ql <= L && R <= qr) return maxv[o];Pushdown(o);int M = (L + R) >> 1;long long ret = 0;if (ql <= M){ret = max(ret, QueryMax(lc, L, M, ql, qr));}if (qr > M){ret = max(ret, QueryMax(rc, M + 1, R, ql, qr));}return ret;
}long long Query(int n, int l, int r, int ql, int qr)
{long long ret = 0;if (ql == qr){ret = r - l + 1;}else{ret = max(ret, QuerySum(1, 1, n, 1, ql) - l + 1);ret = max(ret, r - QuerySum(1, 1, n, 1, qr - 1));if (qr - ql >= 2){ret = max(ret, QueryMax(1, 1, n, ql + 1, qr - 1));}}return ret;
}int main()
{int t, n, m, l, r, ql, qr, kase = 0;char op;scanf("%d", &t);getchar();while (t--){scanf("%d%d", &n, &m);getchar();Build(1, 1, n);printf("Case #%d:\n", ++kase);while (m--){op = getchar(); getchar();l = ReadInt();r = ReadInt();ql = QueryFigure(1, 1, n, l);qr = QueryFigure(1, 1, n, r);if (op == 'D'){Update(n, l, r, ql, qr);}else{printf("%I64d\n", Query(n, l, r, ql, qr));}}}return 0;
}