题意:初始序列 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; }
时间: 2024-10-02 02:29:37