zoukankan      html  css  js  c++  java
  • A simple simulation problem.(线段树)

    题目描述:

    There are n types of cells in the lab, numbered from 1 to n. These cells are put in a queue, the i-th cell belongs to type i. Each time I can use mitogen to double the cells in the interval [l, r]. For instance, the original queue is {1 2 3 3 4 5}, after using a mitogen in the interval [2, 5] the queue will be {1 2 2 3 3 3 3 4 4 5}. After some operations this queue could become very long, and I can’t figure out maximum count of cells of same type. Could you help me?

    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;
    }
  • 相关阅读:
    "密码最短长度为7,其中必须包含以下非字母数字字符1"解决方法 (转)
    关于数据绑定的一个小小的总结:绑定数据到List类型的控件(RadioButtonList,ListBox等),双重绑定。
    转:从玩具到游戏 看另类项目激励机制
    [系列文章]上传文件管理控件之v1
    [系列文章]上传文件管理控件v3
    解决“此版本的 SQL Server 不支持用户实例登录标志。该连接将关闭”问题,完整综合版。
    Crystal Reports基本语法
    Crystal Reports图表(上)
    Crystal Reports第一张报表
    Crystal Reports中的字段
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12738616.html
Copyright © 2011-2022 走看看