hdu 4973 线段树

来源:互联网 发布:淘宝开店装修模板 编辑:程序博客网 时间:2024/05/01 17:40

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)
 

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
15 5D 5 5Q 5 6D 2 3D 1 2Q 1 7
 

Sample Output
Case #1:23
 

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 50005typedef 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;}


0 0