题目描述:
InputThe first line contains a single integer t (1 <= t <= 20), the number of test cases.
For each case, the first line contains 2 integers (1 <= n,m<= 50000) indicating the number of cell types and the number of operations.
For the following m lines, each line represents an operation. There are only two kinds of operations: Q and D. And the format is:
“Q l r”, query the maximum number of cells of same type in the interval [l, r];
“D l r”, double the cells in the interval [l, r];
(0 <= r – l <= 10^8, 1 <= l, r <= the number of all the cells)OutputFor each case, output the case number as shown. Then for each query "Q l r", print the maximum number of cells of same type in the interval [l, r].
Take the sample output for more details.
Solution
处理一个cnt[i]代表颜色i出现的次数
维护一棵线段树,维护区间和。
sum[i]代表前缀和
查询:[a,b]
先找到a的颜色和b的颜色再分类讨论
设其为i,j
1,如果i=j同色,则输出b-a+1;
2,如果j=i+1,则输出max(sum[i]-a+1,b-sum[i])
3,如果j >= i+2,则输出max(max(sum[i]-a+1,b-sum[j-1]),max{cnt[k]})(i<k<j)
如何找到a的颜色
设我们要找x的颜色
在线段树上二分,如果左孩子的和>=x,则递归搜索左孩子
如果小于则地递归搜索右孩子。
时间复杂度:O(N logN)
如何区间修改呢?
和查询类似,先找到a的颜色和b的颜色
设其为i,j
1,如果i=j,则直接单点修改cnt[i]加上j-i+1
2,如果i=j+1,则做两次单点修改cnt[i]加上sum[i]-a+1,cnt[j]加上b-sum[i];
注意这里sum[i]不能分两次求(应该也没有傻子分两次求吧)
3,如果j >= i+2,则对于i,j的操作同操作2,
之后我们对区间(i,j)乘一个2即可
实现就很简单了。
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; const ll N = 50010; struct Segment{ ll sum, mx; ll mul; }tr[N << 2]; ll t, n, m; void push_up(ll p) { tr[p].sum = tr[p << 1].sum + tr[p << 1 | 1].sum; tr[p].mx = max(tr[p << 1].mx, tr[p << 1 | 1].mx); } void push_down(ll p) { if (tr[p].mul > 1) { tr[p << 1].sum *= tr[p].mul; tr[p << 1 | 1].sum *= tr[p].mul; tr[p << 1].mx *= tr[p].mul; tr[p << 1 | 1].mx *= tr[p].mul; tr[p << 1].mul *= tr[p].mul; tr[p << 1 | 1].mul *= tr[p].mul; tr[p].mul = 1; } } void build (ll p, ll l, ll r) { tr[p].mul = 1; if (l == r) { tr[p].sum = tr[p].mx = 1; return; } ll mid = (l + r) >> 1; build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r); push_up(p); } //查询颜色 ll ask_color(ll p, ll l, ll r, ll k) { // cout << l << " " << r << endl; if (l == r) return l; push_down(p); ll num = tr[p << 1].sum; // cout << num << endl; ll mid = (l + r) >> 1; if (k <= num) return ask_color(p << 1, l, mid, k); else return ask_color(p << 1 | 1, mid + 1, r, k - num); } //查询和 ll ask_sum(ll p, ll l, ll r, ll x, ll y) { if (r < x || l > y) return 0; if (x <= l && r <= y) { return tr[p].sum; } push_down(p); ll mid = (l + r) >> 1; return ask_sum(p << 1, l, mid, x, y) + ask_sum(p << 1 | 1, mid + 1, r, x, y); } //查询最值 ll ask_max(ll p, ll l, ll r, ll x, ll y) { if (r < x || l > y) return 0; if (x <= l && r <= y) { return tr[p].mx; } push_down(p); ll mid = (l + r) >> 1; return max(ask_max(p << 1, l, mid, x, y), ask_max(p << 1 | 1, mid + 1, r, x, y)); } //单点修改(+v) void add(ll p, ll l, ll r, ll pos, ll v) { if (l == r) { tr[p].sum += v; tr[p].mx += v; return; } push_down(p); ll mid = (l + r) >> 1; if (pos <= mid) add(p << 1, l, mid, pos, v); else add(p << 1 | 1, mid + 1, r, pos, v); push_up(p); } //区间修改(*2) void multi(ll p, ll l, ll r, ll x, ll y) { if (l > y || r < x) return; if (x <= l && r <= y) { tr[p].mul *= 2; tr[p].sum *= 2; tr[p].mx *= 2; return; } push_down(p); ll mid = (l + r) >> 1; multi(p << 1, l, mid, x, y); multi(p << 1 | 1, mid + 1, r, x, y); push_up(p); } void change(ll l, ll r) { ll i = ask_color(1, 1, n, l); ll j = ask_color(1, 1, n, r); // cout << i << " " << j << endl; if (i == j) { add(1, 1, n, i, r - l + 1); } else { ll sm = ask_sum(1, 1, n, 1, i); ll sm2 = ask_sum(1, 1, n, 1, j - 1); if (i + 1 == j) { add(1, 1, n, i, sm - l + 1); add(1, 1, n, j, r - sm); } else { // cout << sm << endl; add(1, 1, n, i, sm - l + 1); ask_color(1, 1, n, l); // cout << r - sm2 << endl; add(1, 1, n, j, r - sm2); ask_color(1, 1, n, l); multi(1, 1, n, i + 1, j - 1); } } } ll query(ll l, ll r) { ll i = ask_color(1, 1, n, l); ll j = ask_color(1, 1, n, r); // cout << i << " " << j << endl; if (i == j) { return r - l + 1; } else { ll sm = ask_sum(1, 1, n, 1, i); ll sm2 = ask_sum(1, 1, n, 1, j - 1); if (i + 1 == j) { return max(sm - l + 1, r - sm); } else { // cout << ask_sum(1, 1, n, 1, j - 1) << endl; // ll ZSY = max(sm - l + 1, r - ask_sum(1, 1, n, 1, j - 1)); // cout << ZSY << endl; return max(max(sm - l + 1, r - sm2), ask_max(1, 1, n, i + 1, j - 1)); } } } ll CRZzzz; int main() { scanf("%lld", &t); while (t--) { CRZzzz++; scanf("%lld%lld", &n, &m); printf("Case #%lld: ", CRZzzz); build(1, 1, n); while (m--) { char s[5]; ll a, b; scanf("%s%lld%lld", s + 1, &a, &b); if (s[1] == 'D') { change(a, b); } else { printf("%lld ", query(a, b)); } } } return 0; }