hdu 3971

Play With Sequence

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 418    Accepted Submission(s): 211


Problem Description
When the girl was solving GSSX, a serious of tough problems about data structure on SPOJ, something intriguing once again comes to GYZ's mind. That is, for a changing sequences, how to count how many elements in a specific range efficiently.

Without any beneficial idea, as usual, GYZ asks her friend, CLJ for help. But this time, unfortunately, CLJ is playing a gal-game at present, does not have sparse time.

So now , it is your turn...

Cause the original problem is not as easy as first glance, let's examine a simplified one:

you are given a sequence A[1], A[2],..., A[N]. On this sequence you have to apply M operations: Add all the elements whose value are in range [l, r] with d or, ask for a query how many element are in range [l, r].

 

Input
There are only one test case, Process until the end of the file. The first line of each case contains two numbers, N, M, described as above. And then start from the second line, have N numbers described the sequence's initial value.

( 1≤ N ≤ 250,000, M ≤ 50,000), |A[i]|≤ 1,000,000,000 .)

The following M lines described the operation:

C l r d: Add all the element whose value are in range [l, r] with d. (Redeclare: Not its Position! .. ) Q l r: ask for a query how many elements, whose value are in range [l, r].

( l ≤ r, |l|,|r|,|d|≤ 1,000,000,000 )

We guarantee every elements are suits 32-integer, and will not cause overflow, even during the running-time. (.. but still be careful ;) Besides, all the test-data are generated randomly.

 

Output
For each query, print the result. Example
 

Sample Input
  
  
10 10 10 4 -5 8 8 3 0 -2 4 7 C -9 8 2 C -4 10 -3 C -10 0 5 Q -9 -1 C -9 -5 8 C -7 4 3 Q -2 7 C -10 -3 2 C -4 -1 -6 Q 7 10
 

Sample Output
 
 
1 10 4

题意:对有n(0<=n<=250000)个元素的数组A(|A[i]|<=1,000,000,000)进行m(m<=50000)次操作,

一种操作是将所有>=l且<=r的数加上一个数d,另一种操作时求>=l且<=r的数有多少个。

( l ≤ r, |l|,|r|,|d|≤ 1,000,000,000)

解法:首先可以想到线段树,线段树的每个节点存当前区间的最大值和最小值,当然还有延迟标记。但是, 如果就只是这样做,还是会TLE。由于每次更新是将>=l且<=r的数加上一个数d,如果数组A中的元素有序的话, 更新的时候更新的节点就会少一些。因此,我们想A中的元素尽量有序。但也不能每更新一次就将A排序并重新建树, 比较好的方法是操作次数达到一定数量时才将A排序并重新建树。
#include<stdio.h>
#include<algorithm>
#define N 300000
using namespace std;
int val[N];
struct node
{
    int x,y;
    int ma,mi,p;
}a[N*4];
int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}
void pushdown(int t)
{
    int temp=t<<1;
    a[t].ma=max(a[temp].ma,a[temp+1].ma);
    a[t].mi=min(a[temp].mi,a[temp+1].mi);
}
void build(int x,int y,int t)
{
    a[t].x=x;
    a[t].y=y;
    a[t].p=0;
    if(x==y)
    {
        a[t].ma=a[t].mi=val[x];
        return;
    }
    int mid=(x+y)>>1,temp=t<<1;
    build(x,mid,temp);
    build(mid+1,y,temp+1);
    pushdown(t);
}
void fun(int t)
{
   int temp=t<<1;
    if(a[t].p)
    {
        a[temp].p+=a[t].p;
        a[temp].ma+=a[t].p;
        a[temp].mi+=a[t].p;
        a[temp+1].p+=a[t].p;
        a[temp+1].ma+=a[t].p;
        a[temp+1].mi+=a[t].p;
        a[t].p=0;
    }
}
void update(int x,int y,int k,int t)
{
    if(x>a[t].ma||y<a[t].mi)
        return;
    if(x<=a[t].mi&&y>=a[t].ma)
    {
        a[t].p+=k;
        a[t].ma+=k;
        a[t].mi+=k;
        return;
    }
    fun(t);
    int temp=t<<1;
    update(x,y,k,temp);
    update(x,y,k,temp+1);
    pushdown(t);
}
int query(int x,int y,int t)
{
    int ans=0;
    if(x>a[t].ma||y<a[t].mi)
        return 0;
    if(x<=a[t].mi&&y>=a[t].ma)
    {
        return (a[t].y-a[t].x+1);
    }
    fun(t);
    int temp=t<<1;
    ans+=query(x,y,temp);
    ans+=query(x,y,temp+1);
    pushdown(t);
    return ans;
}
void getval(int x,int y,int t)
{
     if(a[t].x==a[t].y)
     {
           val[a[t].x]=a[t].ma;
           return;
     }
     fun(t);
     int mid=(x+y)>>1,temp=t<<1;
     getval(x,mid,temp);
     getval(mid+1,y,temp+1);
     pushdown(t);
}
int main()
{
    int i,n,m,l,r,d;
    char str[10];
    //freopen("a.txt","r",stdin);
     //freopen("b.txt","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1; i<=n; i++)
            scanf("%d",&val[i]);
        sort(val+1,val+1+n);
        build(1,n,1);
        for(i=1; i<=m; i++)
        {
            scanf("%s",str);
            if(str[0]=='C')
            {
                scanf("%d%d%d",&l,&r,&d);
                update(l,r,d,1);
            }
            else
            {
                scanf("%d%d",&l,&r);
                printf("%d\n",query(l,r,1));
            }
            if(i%4000==0)
            {
               getval(1,n,1);
               sort(val+1,val+1+n);
               build(1,n,1);
            }
        }
    }
   return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值