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

Source

2014 Multi-University Training Contest 10

思路:每次操作和查询前找区间端点对应的位置,分情况处理。

#include <stdio.h>
#define max(A,B)(A>B?A:B)

long long sum[200005],att[200005],mx[200005],remain;

void build(int idx,int s,int e)
{
    if(s!=e)
    {
        int mid=(s+e)>>1;

        build(idx<<1,s,mid);
        build(idx<<1|1,mid+1,e);

        sum[idx]=sum[idx<<1]+sum[idx<<1|1];
    }
    else sum[idx]=1;

    att[idx]=0;
    mx[idx]=1;
}

void segupdate(int idx,int s,int e,int l,int r)
{
    if(s==l && r==e)
    {
        sum[idx]*=2;
        mx[idx]*=2;

        att[idx]++;

        return;
    }

    int mid=(s+e)>>1;

    if(att[idx])
    {
        sum[idx<<1]<<=att[idx];
        sum[idx<<1|1]<<=att[idx];

        mx[idx<<1]<<=att[idx];
        mx[idx<<1|1]<<=att[idx];

        att[idx<<1]+=att[idx];
        att[idx<<1|1]+=att[idx];

        att[idx]=0;
    }

    if(r<=mid) segupdate(idx<<1,s,mid,l,r);
    else if(l>mid) segupdate(idx<<1|1,mid+1,e,l,r);
    else
    {
        segupdate(idx<<1,s,mid,l,mid);
        segupdate(idx<<1|1,mid+1,e,mid+1,r);
    }

    sum[idx]=sum[idx<<1]+sum[idx<<1|1];
    mx[idx]=max(mx[idx<<1],mx[idx<<1|1]);
}

void update(int idx,int s,int e,int pos,int val)
{
    if(s==e)
    {
        sum[idx]+=val;
        mx[idx]+=val;

        return;
    }

    if(att[idx])
    {
        sum[idx<<1]<<=att[idx];
        sum[idx<<1|1]<<=att[idx];

        mx[idx<<1]<<=att[idx];
        mx[idx<<1|1]<<=att[idx];

        att[idx<<1]+=att[idx];
        att[idx<<1|1]+=att[idx];

        att[idx]=0;
    }

    int mid=(s+e)>>1;

    if(pos<=mid) update(idx<<1,s,mid,pos,val);
    else update(idx<<1|1,mid+1,e,pos,val);

    sum[idx]=sum[idx<<1]+sum[idx<<1|1];
    mx[idx]=max(mx[idx<<1],mx[idx<<1|1]);
}

int query(int idx,int s,int e,long long val,bool flag)
{
    if(s==e)
    {
        if(flag) remain=sum[idx]-val+1;
        else remain=val;

        return s;
    }

    if(att[idx])
    {
        sum[idx<<1]<<=att[idx];
        sum[idx<<1|1]<<=att[idx];

        mx[idx<<1]<<=att[idx];
        mx[idx<<1|1]<<=att[idx];

        att[idx<<1]+=att[idx];
        att[idx<<1|1]+=att[idx];

        att[idx]=0;
    }

    int mid=(s+e)>>1;

    if(val<=sum[idx<<1]) return query(idx<<1,s,mid,val,flag);
    else return query(idx<<1|1,mid+1,e,val-sum[idx<<1],flag);
}

long long querymax(int idx,int s,int e,int l,int r)
{
    if(s==l && e==r) return mx[idx];

    if(att[idx])
    {
        sum[idx<<1]<<=att[idx];
        sum[idx<<1|1]<<=att[idx];

        mx[idx<<1]<<=att[idx];
        mx[idx<<1|1]<<=att[idx];

        att[idx<<1]+=att[idx];
        att[idx<<1|1]+=att[idx];

        att[idx]=0;
    }

    int mid=(s+e)>>1;

    if(r<=mid) return querymax(idx<<1,s,mid,l,r);
    else if(l>mid) return querymax(idx<<1|1,mid+1,e,l,r);
    else
    {
        long long tempa=querymax(idx<<1,s,mid,l,mid);
        long long tempb=querymax(idx<<1|1,mid+1,e,mid+1,r);

        return max(tempa,tempb);
    }
}

int main()
{
    int T,n,m,l,r,cases=1;
    long long a,b,ar,br,ans;
    char s[5];

    scanf("%d",&T);

    while(T--)
    {
        scanf("%d%d",&n,&m);

        printf("Case #%d:\n",cases++);

        build(1,1,n);

        while(m--)
        {
            scanf("%s%I64d%I64d",s,&a,&b);

            if(s[0]=='D')
            {
                l=query(1,1,n,a,1);
                ar=remain;
                r=query(1,1,n,b,0);
                br=remain;

                if(l==r) update(1,1,n,l,b-a+1);
                else
                {
                    update(1,1,n,l,ar);
                    update(1,1,n,r,br);

                    if(l+1<=r-1) segupdate(1,1,n,l+1,r-1);
                }
            }
            else
            {
                l=query(1,1,n,a,1);
                ar=remain;
                r=query(1,1,n,b,0);
                br=remain;

                if(l==r) printf("%I64d\n",b-a+1);
                else
                {
                    ans=max(ar,br);

                    if(l+1<=r-1) ans=max(ans,querymax(1,1,n,l+1,r-1));

                    printf("%I64d\n",ans);
                }
            }
        }
    }
}
时间: 2024-10-11 12:45:37

HDU-4937-A simple simulation problem.(线段树)的相关文章

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]对应的数字分别是

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.

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

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 -->>因为区间内数字是依次递增的,所以可以以数字为叶建线段

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

HDU 2852 KiKi&#39;s K-Number(线段树+树状数组)

KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2603    Accepted Submission(s): 1202 Problem Description For the k-th number, we all should be very familiar with it. Of course,t

hdu 1394 Minimum Inversion Number(线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10853    Accepted Submission(s): 6676 Problem Description The inversion number of a given number sequence a1, a2, ..., a