HDU4973: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
#include<stdio.h>
#define L 50005
#define ll __int64
#define ls 2*i
#define rs 2*i+1
#define w(x) while(x)
#define max(a,b) (a>b?a:b)
int t,n,m,cas=1;
ll x,y,ans,res;
char str[10];
struct node
{
    int l,r,flag;
    ll maxn,sum;
} a[L<<2];
void PushUp(int i)
{
    a[i].sum=a[2*i].sum+a[2*i+1].sum;
    a[i].maxn=max(a[2*i].maxn,a[2*i+1].maxn);
}
void PushDown(int i)
{
    if(a[i].flag)
    {
        a[ls].flag += a[i].flag;
        a[rs].flag += a[i].flag;
        w(a[i].flag--)
        {
            a[ls].maxn *= 2;
            a[rs].maxn *= 2;
            a[ls].sum *= 2;
            a[rs].sum *= 2;
        }
        a[i].flag=0;
    }
}
void init(int l,int r,int i)
{
    a[i].l=l;
    a[i].r=r;
    a[i].flag=0;
    a[i].maxn=1;
    if(l==r)
    {
        a[i].sum=1;
        return;
    }
    int mid=(l+r)/2;
    init(l,mid,ls);
    init(mid+1,r,rs);
    PushUp(i);
}
int find(int i,ll x,ll &k,ll &tem)
{
    if(a[i].l==a[i].r)
    {
        k=x;
        tem=a[i].sum;
        return a[i].l;
    }
    PushDown(i);
    if(x<=a[ls].sum) return find(ls,x,k,tem);
    else return find(rs,x-a[ls].sum,k,tem);
}
void insert1(int i,int p,ll v)
{
    if(a[i].l==a[i].r)
    {
        a[i].maxn+=v;
        a[i].sum+=v;
        return;
    }
    PushDown(i);
    int mid=(a[i].l+a[i].r)/2;
    if(p<=mid) insert1(ls,p,v);
    else insert1(rs,p,v);
    PushUp(i);
}
void insert2(int l,int r,int i)
{
    if(l<=a[i].l&&a[i].r<=r)
    {
        PushDown(i);
        a[i].flag++;
        a[i].sum*=2;
        a[i].maxn*=2;
        return;
    }
    PushDown(i);
    int mid=(a[i].l+a[i].r)/2;
    if(l<=mid) insert2(l,r,ls);
    if(r>mid) insert2(l,r,rs);
    PushUp(i);
}
void query(int l,int r,int i)
{
    if(l<=a[i].l&&a[i].r<=r)
    {
        res=max(res,a[i].maxn);
        return;
    }
    PushDown(i);
    int mid=(a[i].l+a[i].r)/2;
    if(l<=mid) query(l,r,ls);
    if(r>mid) query(l,r,rs);
}
int main()
{
    scanf("%d",&t);
    w(t--)
    {
        scanf("%d%d",&n,&m);
        init(1,n,1);
        printf("Case #%d:\n",cas++);
        w(m--)
        {
            scanf("%s%I64d%I64d",str,&x,&y);
            ll lk,rk,tem;
            int r=find(1,y,rk,tem);
            int l=find(1,x,lk,tem);
            if(str[0]=='D')
            {
                if(l==r)
                {
                    insert1(1,l,rk-lk+1);
                    continue;
                }
                insert1(1,r,rk);
                insert1(1,l,tem-lk+1);
                if(r-l>1)
                    insert2(l+1,r-1,1);
            }
            else
            {
                ans=0;
                if(l==r)
                {
                    printf("%I64d\n",rk-lk+1);
                    continue;
                }
                ans=max(ans,max(rk,tem-lk+1));
                if(r-l>1)
                {
                    res=0;
                    query(l+1,r-1,1);
                    ans=max(ans,res);
                }
                printf("%I64d\n",ans);
            }
        }
    }
    return 0;
}
时间: 2024-08-30 01:12:27

HDU4973:A simple simulation problem.(线段树)的相关文章

HDU4973A simple simulation problem.(线段树,区间更新)

A simple simulation problem. Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 330    Accepted Submission(s): 132 Problem Description There are n types of cells in the lab, numbered from 1 to n.

hdu 4973 A simple simulation problem.(线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=4973 有两种操作 D l r 将[l,r]区间翻倍 Q l r询问[l,r]中相同数字出现的最多次数 比赛的时候脑子太乱了,没有想到怎么做.发现每次翻倍序列的长度都在变化,区间对应的数也在变,没有思路. 但是静下心来想一想,思路还是挺清晰的. 无论怎么翻倍,序列中的数都是连续的,范围是1~n.可以拿一个数组来记录每个数出现的次数,当更新或询问区间[l,r]时,可以利用其前缀和找到区间[l,r]对应的数字分别是

HDU-4937-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

ZOJ 3686 A Simple Tree Problem(线段树)

A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the labels are 0. We define this kind of operation: given a subtree, negate all its labels. An

bzoj 3489 A simple rmq problem - 线段树

Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直接输出0.我会采取一些措施强制在线. Input 第一行为两个整数N,M.M是询问数,N是序列的长度(N<=100000,M<=200000) 第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N 再下面M行,每行两个整数x,y, 询问区间[l,r]由下列规则产生(OIER

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

Light OJ 1080 - Binary Simulation - (线段树区间更新 单点查询)

Description Given a binary number, we are about to do some operations on the number. Two types of operations can be here. 'I i j'    which means invert the bit from i to j (inclusive) 'Q i'    answer whether the ith bit is 0 or 1 The MSB (most signif

hdu - 4973 - A simple simulation problem.(线段树单点更新 + 区间更新)

题意:初始序列 1, 2, ..., n,m次操作(1 <= n,m<= 50000),每次操作可为: D l r,将区间[l, r]中的所有数复制一次: Q l r,输出区间[l, r]中同一数字个数的最大值. (0 <= r – l <= 10^8, 1 <= l, r <= 序列元素个数) 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4973 -->>因为区间内数字是依次递增的,所以可以以数字为叶建线段

POJ--4973--A simple simulation problem.【线段树】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4973 题意:有一段数字,长度n,数字为1~n,有两种操作,第一种是使区间[l,r]内的所有数字变成两个,长度n随之增大,第二种操作是查询区间[l,r]中相同的数字最多有多少个. 思路:比赛时扫了一眼,看区间要扩大,没有细想就觉得线段树做不了,而且当时没有人交这道题就没管了,然后看解题报告居然真的是线段树...觉得自己好傻逼.因为只有n种数字,n最大50000,线段树维护3个值:第i个数字有多少个(sum