A Simple Problem with Integers(POJ 3468)

A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 132802 Accepted: 41201
Case Time Limit: 2000MS
Description

You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output

4
55
9
15
Hint

The sums may exceed the range of 32-bit integers.

题目大意思:
给定一个数列,有两种操作
1、(输入为Q)查询区间[l,r]数字总和
2、(输入为W)为区间[l,r]加上一个数num
解题思路:

1、用分块,将length为n数列分成根号n块,(最后一块可能会少)然后处理l,r两边各自的分块(朴素处理,也就是说是直接for),最后再直接处理中间分块的。
sum:每一个分块的总合
orz:记录数列
add:中间那一部分可以整个分块整体都要加的加的

时间复杂度:O((N+Q)logN)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>

#define N 200005

using namespace std;

long long add[N];
long long orz[N];
long long sum[N];
char s;
long long l,r;
long m,g,p;
long long num;
long long ans;


int find(long long g)
 {
    if(g%num>=1)
      g=g/num+1;
    else
      g=g/num;
    return g;    

 }


void lookup(long long l,long long r)
 {
    long long x=find(l);//查找左侧l位于哪个区间 
    long long y=find(r);//同理,查找右侧r位于哪个区间 

     if(y-x<=1)//判断l,r是否在相邻或同一个区间,若是直接朴素for过去,更快 
      {
        for(int i=l;i<=r;i++)
         ans+=orz[i]+add[find(i)];
      }
    else
      {
        for(int i=l;i<=num*x;i++)
         ans=ans+orz[i]+add[x];
        for(int i=r;i>=num*(y-1)+1;i--)
          ans=ans+orz[i]+add[y];

         for(int i=x+1;i<=y-1;i++)
          ans=ans+sum[i]+num*add[i];   

      }  
      printf("%lld\n",ans);
//    for(int i=1;i<=m;i++)printf("%d ",orz[i]);
    //         printf("\n");
    //         for(int i=1;i<=sqrt(m)+1;i++)printf("%d ",sum[i]);
    //         printf("\n");
    //         for(int i=1;i<=sqrt(m)+1;i++)printf("%d ",add[i]);
    //         printf("\n");
      ans=0;

 }

 void insert(long long l,long long r,long long www)
  {
    int x=find(l);
    int y=find(r);

    long long xl=0;
    if (num*x>m) xl=m;
       else  xl=num*x;//特判处理左边节点是的区间最右的成员(因为有可能是在最后一个不完全区间) 
    if(x==y)xl=r;          
    for(int i=l;i<=xl;i++)
     {
       orz[i]+=www;
       sum[x]+=www;
     }


    if(x!=y) //判断是否了l,r在同一个区间,防止多加 
     {
       for(int i=r;i>=num*(y-1)+1;i--)
         {
          orz[i]+=www;
          sum[y]+=www;
         }
     }

     for(int i=x+1;i<=y-1;i++)
      add[i]+=www;

  } 

int main()
 {
    //freopen("a.out","w",stdout);
    scanf("%lld %lld",&m,&p);

    for(int i=1;i<=m;i++)
     scanf("%lld",&orz[i]);


     num=sqrt((double)m);//取根号m的整数
    int j=1;
    for(int i=1;i<=m/num;i++)
     {
        int k=1;
        while(k<=num)
         {
            sum[i]+=orz[j];
            j++;
            k++;
         }
     }

     for(int i=j;i<=m;i++)sum[m/num+1]+=orz[i];
     long long t=0;
     long long ss=0;
     long long ber=0;
    for(int i=1;i<=p;i++)
     {
       cin>>s;
       switch(s)
        {
            case 'Q':scanf("%lld %lld",&t,&ss);
                     lookup(t,ss);
                     break;
            case 'C':scanf("%lld %lld %lld",&t,&ss,&ber);
                     insert(t,ss,ber);
                     break;
        }
     }
    return 0;  
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值