hdu 4973 A simple simulation problem(线段树)

题意:有n种细胞,分别从1到n编号,有两种操作,一种是将第l到第r个细胞加倍,另一种是查询区间[l,r]中那种细胞数量最多,求最多的数量。

思路:比赛后10分钟A掉了,简直不能再感人。。。用线段树维护三个值:sum区间细胞数量,maxv区间中数量最多的细胞,mul区间中细胞需要翻的倍数。因为是将一个种类的细胞数量放在了一起,那么对于查询或更新,都要处理一下边界问题,比如查询吧,首先要看第r个细胞是哪种细胞,是否l细胞在包括在这个细胞内了,然后同样查询第l个细胞,然后,对于介于这两种细胞之间的细胞,就可以放心地线段树查询了。对于更新操作也是一样的,这里需要注意,一定要先查询右端点,因为如果要更新左端点的话,右端点就不能准确地找到了,剩下就基本没什么问题了,细心点写就ok了。。


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#include<assert.h>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn = 50000+10;
ll maxv[maxn<<2],sum[maxn<<2],mul[maxn<<2],ans;
inline void PushUp(int rt)
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    maxv[rt] = max(maxv[rt<<1],maxv[rt<<1|1]);
}
void PushDown(int rt)
{
    if(mul[rt] > 1)
    {
        mul[rt<<1] *= mul[rt];
        mul[rt<<1|1] *= mul[rt];
        maxv[rt<<1] = maxv[rt<<1]*mul[rt];
        maxv[rt<<1|1] = maxv[rt<<1|1]*mul[rt];
        sum[rt<<1] = sum[rt<<1]*mul[rt];
        sum[rt<<1|1] = sum[rt<<1|1]*mul[rt];
        mul[rt] = 1;
    }
}
void build(int l,int r,int rt)
{
    mul[rt] = 1;
    if(l == r)
    {
        sum[rt] = maxv[rt] = 1;
        return ;
    }
    int m =(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    PushUp(rt);
}
int Qleft(ll k,ll tot,int l,int r,int rt,int type)
{
    if(l == r)
    {
        if(type == 0)
        {
            if(sum[rt] - k + 1 >= tot)
            {
                ans = tot;
                return -1;
            }
            ans = max(ans,sum[rt]-k+1);
            return l + 1;
        }
        else
        {
            if(sum[rt] - k + 1 >= tot)
            {
                sum[rt] += tot;
                maxv[rt] += tot;
                return -1;
            }
            maxv[rt] += sum[rt]-k+1;
            sum[rt] += sum[rt]-k+1;
            return l + 1;
        }
    }
    PushDown(rt);
    int m = (l+r)>>1;
    int res;
    if(sum[rt<<1]>=k) res = Qleft(k,tot,l,m,rt<<1,type);
    else res = Qleft(k - sum[rt<<1],tot,m+1,r,rt<<1|1,type);
    PushUp(rt);
    return res;
}
int Qright(ll k,ll tot,int l,int r,int rt,int type)
{
    if(l == r)
    {
        if(type == 0)
        {
            if(tot <= k)
            {
                ans = tot;
                return -1;
            }
            ans = max(ans,k);
            return r - 1;
        }
        else
        {
            if(tot<=k)
            {
                sum[rt] += tot;
                maxv[rt] += tot;
                return -1;
            }
            sum[rt] += k;
            maxv[rt] += k;
            return r - 1;
        }
    }
    PushDown(rt);
    int m = (l+r)>>1;
    int res ;
    if(sum[rt<<1]>=k) res = Qright(k,tot,l,m,rt<<1,type);
    else res = Qright(k - sum[rt<<1],tot,m+1,r,rt<<1|1,type);
    PushUp(rt);
    return res;
}
ll Query(int L,int R,int l,int r,int rt)
{
    if(l >= L && r <= R)
    {
        return maxv[rt];
    }
    PushDown(rt);
    int m = (l + r)>>1;
    ll res = 0;
    if(m >= L) res = max(res,Query(L,R,l,m,rt<<1));
    if(m < R) res = max(res ,Query(L,R,m+1,r,rt<<1|1));
    return res;
}
void Update(int L,int R,int l,int r,int rt)
{
    if(l >= L && r <= R)
    {
        mul[rt] *= 2;
        sum[rt] *= 2;
        maxv[rt] *= 2;
        return ;
    }
    PushDown(rt);
    int m = (l + r)>>1;
    if(m >= L) Update(L,R ,l,m,rt<<1);
    if(m < R) Update(L,R,m+1,r,rt<<1|1);
    PushUp(rt);
}
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int t,n,m,tcase = 0;
    char str[10];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        build(1,n,1);
        ll l,r;
        int L,R;
        printf("Case #%d:\n",++tcase);
        while(m--)
        {
            scanf("%s%I64d%I64d",str,&l,&r);
            if(str[0] == 'D')
            {
                R = Qright(r,r-l+1,1,n,1,1);
                if(R != -1) L = Qleft(l,r-l+1,1,n,1,1);
                if(L != -1 && R != -1 && L <= R)
                {
                    Update(L,R,1,n,1);
                }
            }
            else
            {
                ans = 0;
                R = Qright(r,r-l+1,1,n,1,0);
                if(R != -1) L = Qleft(l,r-l+1,1,n,1,0);
                if(L != - 1&& R != - 1 && L <= R)
                {
                    ans = max(ans,Query(L,R,1,n,1));
                }
                printf("%I64d\n",ans);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值