HDU4267(线段树 +有规律的多个端点更新)

A Simple Problem with Integers

Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5765    Accepted Submission(s): 1847


Problem Description
Let A1, A2, ... , AN be N elements. You need to deal with two kinds of operations. One type of operation is to add a given number to a few numbers in a given interval. The other is to query the value of some element.
 

Input
There are a lot of test cases.
The first line contains an integer N. (1 <= N <= 50000)
The second line contains N numbers which are the initial values of A1, A2, ... , AN. (-10,000,000 <= the initial value of Ai <= 10,000,000)
The third line contains an integer Q. (1 <= Q <= 50000)
Each of the following Q lines represents an operation.
"1 a b k c" means adding c to each of Ai which satisfies a <= i <= b and (i - a) % k == 0. (1 <= a <= b <= N, 1 <= k <= 10, -1,000 <= c <= 1,000)
"2 a" means querying the value of Aa. (1 <= a <= N)
 

Output
For each test case, output several lines to answer all query operations.
 

Sample Input
  
  
4 1 1 1 1 14 2 1 2 2 2 3 2 4 1 2 3 1 2 2 1 2 2 2 3 2 4 1 1 4 2 1 2 1 2 2 2 3 2 4
 

Sample Output
  
  
1 1 1 1 1 3 3 1 2 3 4 1
 
题意:给定一个数组A,然后进行两种操作 1.对 a,b区间内任意i,如果(i-a)%k==0,则将Ai的值加上c;2.输入任意a,输出Aa的值。
分析:对一段区间内的数进行操作,首先想到线段树。如果用端点更新,根据数据范围,则肯定会超时。所以只能进行区间延时更新。
那么要找出这段数的规律。(i-a)%k==0,则i和a膜k的余数相等。由于k的范围是10以内,加上余数 , 总共有55种不同的k和余数(这能成为一种标记,表示对查询x,是否可以加上c)、
55*50000*4,勉勉强强可以过。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define Lson  l,mid,rt<<1       // rt:根节点
#define Rson  mid+1,r,rt<<1|1
#define N 50005
int x,n,m,add[N*4][55],seg[N*4],d[11][11],t[N];  //用d[][]来映射 ,节省空间
void build(int l,int r,int rt)
{
    for(int i=0;i<55;i++)
        add[rt][i]=0;
    if(l==r)
    {
        seg[rt]=t[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(Lson);
    build(Rson);
}
void update(int b,int e,int c,int k,int mo,int l,int r,int rt)
{
    if(b<=l&&r<=e)
    {
        add[rt][d[k][mo]]+=c;
        return ;
    }
    int mid=(l+r)>>1;
    if(b<=mid)update(b,e,c,k,mo,Lson);
    if(e>mid)update(b,e,c,k,mo,Rson);
    return ;
}
void pushup(int x,int l,int r,int rt)
{
    for(int i=1;i<=10;i++)
        {  int xx=x%i;
            if(add[rt][d[i][xx]])
    {
        add[rt<<1][d[i][xx]]+=add[rt][d[i][xx]];
        add[rt<<1|1][d[i][xx]]+=add[rt][d[i][xx]];
        add[rt][d[i][xx]]=0;
    }
        }
}
int query(int x,int l,int r,int rt)
{
    if(l==r&&x==l)
    {
        //seg[rt]+=cov[rt];
        //cov[rt]=0;
        for(int i=1;i<=10;i++)
        {
            seg[rt]+=add[rt][d[i][x%i]];
            add[rt][d[i][x%i]]=0;
        }
        return seg[rt];
    }
    int mid=(l+r)/2;
    pushup(x,l,r,rt);
    if(x<=mid)return query(x,Lson);
    else return query(x,Rson);
}
int main()
{
    int tot=0;
    for(int i=1;i<=10;i++)
        for(int j=0;j<i;j++)
        d[i][j]=tot++;  //每种对应一种状态 i代表k,j代表余数
    //cout<<tot<<endl;
    //cout<<sizeof(add)/1024/1024;
    int a,b,k,c;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)scanf("%d",&t[i]);
        build(1,n,1);
        //memset(add,0,sizeof(add));
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&tot);
            if(tot==1)
            {
                scanf("%d%d%d%d",&a,&b,&k,&c);
               update(a,b,c,k,a%k,1,n,1);
            }
            else
            {
                scanf("%d",&a);
                //for(int a=1;a<=n;a++)
                printf("%d\n",query(a,1,n,1));
            }
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值