hdu4267分组线段树

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

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
/***
hdu4267分组线段树
题目大意:对于给定区间[a,b]的数(i-a)%k==0加上c,最后单点查询。
解题思路:分组为[a,b]区间内除k余m的分为一组。这样按组来更新就好了。
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <iostream>
using namespace std;
const int maxn=50010;

int tree[maxn*4][55];
int flag[maxn*4];
int b[11][11],num[maxn];

void build(int l,int r,int root)
{
    flag[root]=0;
    for(int i=0;i<55;i++)
    {
        tree[root][i]=0;
    }
    if(l==r)return;
    int mid=(l+r)/2;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
}

void push_down(int root)
{
    if(flag[root])
    {
        flag[root<<1|1]=flag[root<<1]=flag[root];
        flag[root]=false;
        for(int i=0;i<55;i++)
        {
            tree[root<<1][i]+=tree[root][i];
            tree[root<<1|1][i]+=tree[root][i];
            tree[root][i]=0;
        }
    }
}

int query(int pos,int l,int r,int root)
{
    if(l==r)
    {
        int ret=0;
        for(int i=1;i<=10;i++)
        {
            ret+=tree[root][b[i][pos%i]];
        }
        return ret;
    }
    push_down(root);
    int m=(l+r)/2;
    if(pos<=m)
        return query(pos,l,m,root<<1);
    else
        return query(pos,m+1,r,root<<1|1);
}

void update(int mod,int L,int R,int k,int c,int l,int r,int root)
{
    if(L<=l&&r<=R)
    {
       /// printf("*\n");
        tree[root][b[k][mod]]+=c;
        flag[root]=true;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid)
        update(mod,L,R,k,c,l,mid,root<<1);
    if(mid<R)
        update(mod,L,R,k,c,mid+1,r,root<<1|1);
}

int main()
{
    int cnt=0;
    for(int i=1;i<11;i++)///分组
    {
        for(int j=0;j<i;j++)
            b[i][j]=cnt++;
    }
    int n,m;
    while(~scanf("%d",&n))
    {
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        scanf("%d",&m);
        while(m--)
        {
            int x;
            scanf("%d",&x);
            if(x==1)
            {
                int u,v,k,c;
                scanf("%d%d%d%d",&u,&v,&k,&c);
                update(u%k,u,v,k,c,1,n,1);
            }
            else
            {
                int pos;
                scanf("%d",&pos);
                printf("%d\n",query(pos,1,n,1)+num[pos]);
            }
        }
    }
    return 0;
}

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
时间: 2024-12-28 17:46:17

hdu4267分组线段树的相关文章

HDU4267 A Simple Problem with Integers 线段树/树状数组

HDU4267 A Simple Problem with Integers  线段树/树状数组 2012长春网络赛A题 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. T

hdu4267 线段树

开始敲了一发线段树,觉得可以暴力一点的过,tle了.后来进行修改,发现了问题. 后来一看大神的做法,由于1<=k<=10,所以对于不同的k,有55个余,找答案的时候只要找不同的k值满足条件的值. 成段更新时,更新全部的树即可. #include<stdio.h> #include<string.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 50010;

hdu4267---A Simple Problem with Integers(线段树)

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

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放

HDU 4288 Coder (线段树)

Coder 题目:http://acm.hdu.edu.cn/showproblem.php?pid=4288 题意:有三种类型的操作,(1)."add x",表示往集合里加入?数x.(2)."del x"表示将集合中数x删除.(3)."sum"求出从小到大排列的集合中下标模5为3的数的和.集合中的数都是唯一的. 思路:这题巧妙的地方在于先离线输入,然后离散化.输入的数字依照从小到大排序,然后作为线段树的叶子结点.每一个结点包括两个部分,一是该结

【8.23校内测试】【贪心】【线段树优化DP】

$m$的数据范围看起来非常有问题??仔细多列几个例子可以发现,在$m<=5$的时候,只要找到有两行状态按位$&$起来等于$0$,就是可行方案,如果没有就不行. #include<iostream> #include<cstdio> #include<cstring> using namespace std; int cnt[1<<4+1], n, m; int main ( ) { freopen ( "prob.in",

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间