hdu4973 A simple simulation problem.(成段更新+下标转化)


http://acm.hdu.edu.cn/showproblem.php?pid=4973

题意:给你一串连续升序数字和两种操作,D表示将[l, r]区间内的元素个数加倍,Q表示查询[l,r]区间内的最大元素个数。


ps:看的别人的博客。。草。。


思路:既然元素再怎么加倍也总是连续的,那么每个不同元素当做线段树子节点,开一个sum域表示同种元素的个数。于是难点就转化为了实际区间转化为线段树区间,只有找到线段树中的相对区间,才可以进行一系列加倍操作。我们这里传递一个st值,st代表查询更新区间的左节点,st+tree[i].sum-1代表查询更新区间的右节点,分别代表查询时的l与r。那么在线段树中递归时,tree[i]就代表递归到了线段树的第几层。传递时的中值就是mid = st-1+tree[i*2].sum,是按照大的更新区间方式传递,而非线段树区间。只要搞清这点就好办了,区间加倍就是找到对应区间直接对其总数与最值加倍,无需对端点特殊处理。这里我犯了个很SB的错,查询时push_down写成了push_up,问题是输入的样例还没问题,检查了我半天。。


#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>

using namespace std;

typedef long long LL;

const int N = 100010;
const int INF = 1e8;

struct line
{
    __int64 l, r;
    __int64 sum;
    __int64 maxx;
    __int64 lazy;
}tree[8*N];

void push_up(__int64 i)
{
    tree[i].maxx = max(tree[i*2].maxx, tree[i*2+1].maxx);
    tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;
    return;
}

void push_down(__int64 i)
{
    if(tree[i].l == tree[i].r || tree[i].lazy == 0) return;
    tree[i*2].lazy += tree[i].lazy;
    tree[i*2+1].lazy += tree[i].lazy;
    tree[i*2].maxx <<= tree[i].lazy;
    tree[i*2].sum <<= tree[i].lazy;
    tree[i*2+1].maxx <<= tree[i].lazy;
    tree[i*2+1].sum <<= tree[i].lazy;
    tree[i].lazy = 0;
}

void build(__int64 i, __int64 l, __int64 r)
{
    tree[i].l = l;
    tree[i].r = r;
    tree[i].lazy = 0;
    if(l == r)
    {
        tree[i].sum = (__int64)1;
        tree[i].maxx = (__int64)1;
        return;
    }
    __int64 mid = (l+r) >> (__int64)1;
    build(i*2, l, mid);
    build(i*2+1, mid+1, r);
    push_up(i);
}

void update(__int64 i, __int64 l, __int64 r, __int64 st)
{
    if(st == l && st+tree[i].sum-1 == r)
    {
        tree[i].lazy++;
        tree[i].maxx <<= (__int64)1;
        tree[i].sum <<= (__int64)1;
        return;
    }
    if(tree[i].l == tree[i].r)
    {
        tree[i].sum += (__int64)(r-(l-1));//这个一定要在前面
        tree[i].maxx = tree[i].sum;
        return;
    }
    push_down(i);
    __int64 mid = st-1+tree[i*2].sum;
    if(mid >= r)
        update(i*2, l, r, st);
    else if(mid < l)
        update(i*2+1, l, r, mid+1);
    else
    {
        update(i*2, l, mid, st);
        update(i*2+1, mid+1, r, mid+1);
    }
    push_up(i);
}

__int64 query(__int64 i, __int64 l, __int64 r, __int64 st)
{
    if(st == l && st-1+tree[i].sum == r)
    {
        return tree[i].maxx;
    }
    if(tree[i].l == tree[i].r)
    {
        return (__int64)(r-(l-1));
    }
    push_down(i);
    __int64 mid = st-1+tree[i*2].sum;
    if(mid >= r)
        return query(i*2, l, r, st);
    else if(mid < l)
        return query(i*2+1, l, r, mid+1);
    else
    {
        return max(query(i*2, l, mid, st),query(i*2+1, mid+1, r, mid+1));
    }
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    __int64 t, n, m, l, r, Case = 1;
    char s[5];
    scanf("%I64d", &t);
    while(t--)
    {
        scanf("%I64d%I64d", &n, &m);
        build(1, 1, n);
        printf("Case #%I64d:\n", Case++);
        for(__int64 i = 1; i <= m; i++)
        {
            scanf("%s", s);
            if(s[0] == 'D')
            {
                scanf("%I64d%I64d", &l, &r);
                update(1, l, r, 1);
            }
            else if(s[0] == 'Q')
            {
                scanf("%I64d%I64d", &l, &r);
                printf("%I64d\n", query(1, l, r, 1));
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值