hdu 4973

题意:

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



     
     
    
    
   
   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值