hdu 4973 A simple simulation problem 线段树

Problem Description
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?
 

Input
The 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)
 

Output
For 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.
 

Sample Input
  
  
1 5 5 D 5 5 Q 5 6 D 2 3 D 1 2 Q 1 7
 

Sample Output
  
  
Case #1: 2 3

  一开始1-N,D是把区间数翻倍,Q询问区间最多多少个连续数。

  做法类似于以前分房间的那个。

  最后不管怎么复制,都是个1到N的不减序列。用sum[o]表示区间有多少个数,maxv[o]表示区间最大连续个数,mul[o]表示区间翻倍数,mul用来pushdown。

  update的时候在[L,R]这些数里找排在第[ql,qr]的,如果sum[o<<1]>=qr,就在左区间找[ql,qr],如果sum[p<<1]>ql就在右区间找[ql-sum[o<<1]],qr-sum[o<<1]],否则就在左边找[ql,sum[o<<1]],右区间找[1,qr-sum[o<<1]]。查询原理也一样。

  要注意更新的时候如果左右都要更新,那么先更新右边,因为先更新左边的话sum[o<<1]可能会变。

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<stack>
#define INF 0x3f3f3f3f
#define MAXN 50010
#define MAXM 110
#define MOD 1000000007
#define MAXNODE 4*MAXN
#define eps 1e-9
using namespace std;
typedef long long LL;
LL T,N,M;
char op[10];
LL sum[MAXNODE],maxv[MAXNODE],mul[MAXNODE];
void maintain(LL o){
    sum[o]=sum[o<<1]+sum[o<<1|1];
    maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);
}
void build(LL o,LL L,LL R){
    mul[o]=0;
    if(L==R){
        maxv[o]=sum[o]=1;
        return;
    }
    LL mid=(L+R)>>1;
    build(o<<1,L,mid);
    build(o<<1|1,mid+1,R);
    maintain(o);
}
void pushdown(LL o){
    if(mul[o]){
        LL lc=o<<1,rc=o<<1|1;
        sum[lc]<<=mul[o];
        sum[rc]<<=mul[o];
        maxv[lc]<<=mul[o];
        maxv[rc]<<=mul[o];
        mul[lc]+=mul[o];
        mul[rc]+=mul[o];
        mul[o]=0;
    }
}
void update(LL o,LL L,LL R,LL ql,LL qr){
    if(L==R){
        sum[o]+=qr-ql+1;
        maxv[o]=sum[o];
        return;
    }
    if(sum[o]==qr-ql+1){
        mul[o]++;
        sum[o]<<=1;
        maxv[o]<<=1;
        return;
    }
    pushdown(o);
    LL mid=(L+R)>>1;
    if(sum[o<<1]>=qr) update(o<<1,L,mid,ql,qr);
    else if(sum[o<<1]<ql) update(o<<1|1,mid+1,R,ql-sum[o<<1],qr-sum[o<<1]);
    else{
        update(o<<1|1,mid+1,R,1,qr-sum[o<<1]);
        update(o<<1,L,mid,ql,sum[o<<1]);
    }
    maintain(o);
}
LL query(LL o,LL L,LL R,LL ql,LL qr){
    if(L==R) return qr-ql+1;
    if(sum[o]==qr-ql+1) return maxv[o];
    pushdown(o);
    LL mid=(L+R)>>1;
    if(sum[o<<1]>=qr) return query(o<<1,L,mid,ql,qr);
    else if(sum[o<<1]<ql) return query(o<<1|1,mid+1,R,ql-sum[o<<1],qr-sum[o<<1]);
    else return max(query(o<<1,L,mid,ql,sum[o<<1]),query(o<<1|1,mid+1,R,1,qr-sum[o<<1]));
}
int main(){
    freopen("in.txt","r",stdin);
    scanf("%I64d",&T);
    LL cas=0;
    while(T--){
        printf("Case #%I64d:\n",++cas);
        scanf("%I64d%I64d",&N,&M);
        build(1,1,N);
        while(M--){
            LL ql,qr;
            scanf("%s",op);
            scanf("%I64d%I64d",&ql,&qr);
            if(op[0]=='D') update(1,1,N,ql,qr);
            else printf("%I64d\n",query(1,1,N,ql,qr));
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值