hdu 4973 A simple simulation problem 线段树 2014 Multi-University Training Contest 10-1003

题意:

一开始给定一个n长序列,元素为1~n。之后又m个询问,共两种:

1)D a b,将[a,b]区间内的元素double,如{1,2,3,4,5}询问D 4 5,则得到{1,2,3,4,4,5,5}

2)Q a b,输出[a,b]区间内重复次数最多的数的个数。


题解:

我们需要维护一个数组cnt[i],表示i的出现次数。那么i的出现位置是[sum[i-1]+1,sum[i]],其中sum[i]表示1到i出现的总次数。

对于D操作,我们找到a位置对应的数字l,b位置对应的数字r。[l,r]区间内的所有cnt[i]都个数翻倍,而对于l和r上的数字则加上相应的个数。b-a<=1e8,,即每次增加个数不会超过10^8,所以总个数不会超过5*10^12。需要用到__int64。

由于n和m很大,所以需要用线段树来维护。


代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cctype>
using namespace std;

#define LL __int64
#define lc (c<<1)
#define rc (c<<1|1)
const int maxn=5e4+10;
struct node{
    LL sum,setv,maxv;
    int l,r;
}e[maxn*4];
LL ans,sum_pre,ll,rr;
int l,r;
void build(int a,int b,int c)
{
    if(a==b)
    {
        e[c].l=e[c].r=a;
        e[c].sum=e[c].maxv=e[c].setv=1;
        return ;
    }
    int mid=(a+b)>>1;
    build(a,mid,lc);
    build(mid+1,b,rc);
    e[c].l=a;
    e[c].r=b;
    e[c].sum=e[lc].sum+e[rc].sum;
    e[c].setv=e[c].maxv=1;
}
void push_down(int c)
{
    if(e[c].setv!=1)
    {
        e[lc].setv*=e[c].setv;e[rc].setv*=e[c].setv;
        e[lc].sum*=e[c].setv;e[rc].sum*=e[c].setv;
        e[lc].maxv*=e[c].setv;e[rc].maxv*=e[c].setv;
        e[c].setv=1;
    }
}
void push_up(int c)
{
    e[c].sum=e[lc].sum+e[rc].sum;
    e[c].maxv=max(e[lc].maxv,e[rc].maxv);
}
void update1(LL a,int c,int flag)//找到a和b对应的位置l和r
{

    if(e[c].l==e[c].r)
    {
        if(flag)
        {
            rr=a-sum_pre;
            r=e[c].l;
        }
        else
        {
            ll=e[c].sum+sum_pre-a+1;
            l=e[c].l;
        }
        return ;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(a>sum_pre+e[lc].sum)
    {
        sum_pre+=e[lc].sum;
        update1(a,rc,flag);
    }
    else
        update1(a,lc,flag);
}
void update2(int a,int b,int c)
{
    if(a>b)return ;
    if(e[c].l==a&&e[c].r==b)
    {
        e[c].setv*=2;
        e[c].sum*=2;
        e[c].maxv*=2;
        return ;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)update2(a,b,lc);
    else if(a>mid)update2(a,b,rc);
    else
    {
        update2(a,mid,lc);
        update2(mid+1,b,rc);
    }
    push_up(c);
}
void update3(int a,int b,int c,LL val)
{
    if(e[c].l==a&&e[c].r==b)
    {
        e[c].sum+=val;
        e[c].maxv+=val;
        return ;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)update3(a,b,lc,val);
    else if(a>mid)update3(a,b,rc,val);
    push_up(c);
}

int query2(int a,int b,int c)
{
    if(e[c].l==a&&e[c].r==b)
    {
        return e[c].sum;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)return query2(a,b,lc);
    else if(a>mid)return query2(a,b,rc);
}
LL query(int a,int b,int c)
{
    if(e[c].l==a&&e[c].r==b)
    {
        return e[c].maxv;
    }
    push_down(c);
    int mid=(e[c].l+e[c].r)>>1;
    if(b<=mid)return query(a,b,lc);
    else if(a>mid)return query(a,b,rc);
    else return max(query(a,mid,lc),query(mid+1,b,rc));
}
int main()
{
    int T,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k,n,m;
        LL a,b;
        char s[2];
        scanf("%d%d",&n,&m);
        build(1,n,1);
        printf("Case #%d:\n",++tt);
        for(i=0;i<m;i++)
        {
            scanf("%s%I64d%I64d",s,&a,&b);
            if(s[0]=='D')
            {
                sum_pre=0;
                update1(a,1,0);
                sum_pre=0;
                update1(b,1,1);
                if(l==r)update3(l,r,1,b-a+1);
                else
                {
                    update3(l,l,1,ll);
                    update3(r,r,1,rr);
                }
                update2(l+1,r-1,1);
            }
            else
            {
                ans=0;
                sum_pre=0;
                update1(a,1,0);
                sum_pre=0;
                update1(b,1,1);
                //printf("*%d %d %I64d %I64d %I64d\n",l,r,ll,rr,b-a+1);
                if(l==r)ans=max(ans,b-a+1);
                else
                {
                    ans=max(ans,ll);
                    ans=max(ans,rr);
                }
                if(l+1<=r-1)ans=max(ans,query(l+1,r-1,1));
                printf("%I64d\n",ans);
            }
        }
        //for(i=1;i<=n;i++)printf("%d\n",query2(i,i,1));
    }
    return 0;
}
/*
1
5 5
D 1 5
D 5 7
Q 8 10
D 1 9
Q 1 15
*/




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值