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)
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.
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;
}