A simple simulation problem.
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 698 Accepted Submission(s): 274
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
Source
2014 Multi-University Training Contest 10
/*有两种操作
D l r 将【l,r】区间翻倍
Q l r询问[l,r]中相同数字出现的最多次数
无论怎么翻倍,序列中的数都是连续的,范围是1~n。可以拿一个变量来记录每个数出现的次数,
当更新或询问区间[l,r]时,可以利用其前缀和找到区间[l,r]对应的数字分别是lx,rx,对于
lx+1,rx-1内的数字是完全翻倍的,可以用线段树维护区间的和以及相同数字的最大数目,
由于l,r并不一定完全包含在lx.rx内,端点需要特殊处理。
那么重点就是怎样找到l,r对应的数更新区间[lx,rx],可以把每个数字所在区间的左端点作为
连接l,r和lx,rx的纽带,根据左端点求出右端点。*/
#include<stdio.h>
#define N 50005
typedef long long ll;
struct node
{
int x,y;
ll sum,mx,p;
}a[N*4];
ll max(ll a,ll b)
{
return a>b?a:b;
}
void pushup(int t)
{
int temp=t<<1;
a[t].sum=a[temp].sum+a[temp+1].sum;
a[t].mx=max(a[temp].mx,a[temp+1].mx);
}
void build(int t,int x,int y)
{
a[t].x=x; a[t].y=y; a[t].p=0;
if(x==y)
{
a[t].sum=a[t].mx=1;
return;
}
int mid=(x+y)>>1,temp=t<<1;
build(temp,x,mid);
build(temp+1,mid+1,y);
pushup(t);
}
void pushdown(int t)
{
int temp=t<<1;
if(a[t].p)
{
a[temp].p+=a[t].p;
a[temp+1].p+=a[t].p;
a[temp].sum<<=a[t].p;
a[temp+1].sum<<=a[t].p;
a[temp].mx<<=a[t].p;
a[temp+1].mx<<=a[t].p;
a[t].p=0;
}
}
void update(ll st,ll x,ll y,int t)
{//st是该节点的左端点在序列中的下标,那么可知这个节点所在区间是[st,st+a[t].sum-1]。
if(st==x&&st+a[t].sum-1==y)
{
a[t].p++;
a[t].sum*=2;
a[t].mx*=2;
return;
}
if(a[t].x==a[t].y)
{//更新部分
a[t].sum+=(y-x)+1;
a[t].mx=a[t].sum;
return;
}
pushdown(t);
int temp=t<<1;
ll mid=st+a[temp].sum-1;
if(y<=mid)
update(st,x,y,temp);
else if(x>mid)
update(mid+1,x,y,temp+1);
else
{
update(st,x,mid,temp);
update(mid+1,mid+1,y,temp+1);
}
pushup(t);
}
ll query(ll st,ll x,ll y,int t)
{
ll ans;
if(st==x&&y==st+a[t].sum-1)
return a[t].mx;
if(a[t].x==a[t].y)
return (y-x+1);
int temp=t<<1;
pushdown(t);
ll mid=st+a[temp].sum-1;
if(y<=mid)
ans=query(st,x,y,temp);
else if(x>mid)
ans=query(mid+1,x,y,temp+1);
else
{
ll m1,m2;
m1=query(st,x,mid,temp);
m2=query(mid+1,mid+1,y,temp+1);
ans=max(m1,m2);
}
pushup(t);
return ans;
}
int main()
{
int t,cnt=1,n,m;
char str[10];
ll l,r;
//freopen("a.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,1,n);
printf("Case #%d:\n",cnt++);
while(m--)
{
scanf("%s%I64d%I64d",str,&l,&r);
if(str[0]=='D')
update(1,l,r,1);
else
printf("%I64d\n",query(1,l,r,1));
}
}
return 0;
}