hdu 4267 A Simple Problem with Integers 线段树,区间部分更新

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

题意:

给你N个数,有两种操作:

2 x询问a[x]的值;

1 a b k c   a <= i <= b 满足(i - a)%k == 0的a[i] += c;

(1 <= N <= 50000) (1 <= a <= b <= N, 1 <= k <= 10, -1,000 <= c <= 1,000)

思路:

一看就知道这肯定是线段树的题目,可是区间内满足(i - a)%k == 0的点才进行处理怎么办,如果i i + k,i + 2k的循环处理的话,就都变成的了单点更新了,时间复杂度O(n^2)就不行可。

这里肯定要优化到O(nlogn),才开始想记录1操作,区间[a,b]按平常加,每次询问点时再枚举所有的1减去多加了,发现只能优化到O(n^2/2)写了一下TLE.后来看了解题报告才恍然大悟。

线段树上的每个点表示一个区间,我们记录该区间所有模i于j的点的值,由于1 <= k <= 10 所以总共有55中可能,把每个区间的所有可能记录,然后区间更新时,只要将该区间所有满足的情况累加一边就好了,单点询问的话只需要将所有情况累加即可。

i%k = a%k;

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll __int64
#define inf 0x7f7f7f7f
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 50007
using namespace std;
//freopen("din.txt","r",stdin);

struct node{
    int l,r;
    int mod[55];//记录模k的各种情况
    int lz;
    int mid(){
       return (l + r)>>1;
    }
}a[4*N];
int mk[11][11],b[N];

void init(){
    int i,j;
    int ct = 0;
    for (i = 1; i <= 10; ++i){
        for (j = 0; j < i; ++j)
        mk[i][j] = ct++;//将其转变为1维
    }
}
void pushdown(int rt){
    if (a[rt].lz){
        a[rt<<1].lz += a[rt].lz;
        a[rt<<1|1].lz += a[rt].lz;
        a[rt].lz = 0;
        for (int i = 0; i < 55; ++i){
            a[rt<<1].mod[i] += a[rt].mod[i];
            a[rt<<1|1].mod[i] += a[rt].mod[i];
            a[rt].mod[i] = 0;
        }
    }
}
void build(int l,int r,int rt){
    a[rt].l = l; a[rt].r = r;
    a[rt].lz = 0;
    CL(a[rt].mod,0);
    if (l == r) return;
    int m = a[rt].mid();
    build(lc);
    build(rc);
}
void update(int L,int R,int k,int MOD,int sc,int rt){
    if (a[rt].l >= L && a[rt].r <= R){
        a[rt].lz += sc;
        a[rt].mod[mk[k][MOD]] += sc;//模k等于MOD的累加
        return;
    }
    pushdown(rt);
    int m = a[rt].mid();
    if (L <= m) update(L,R,k,MOD,sc,rt<<1);
    if (R > m) update(L,R,k,MOD,sc,rt<<1|1);
}
int query(int pos,int rt){
    if (a[rt].l == a[rt].r){
        int tmp = 0;
        for (int i = 1; i <= 10; ++i){
            tmp += a[rt].mod[mk[i][pos%i]];//枚举当前点模1-10的所有可能
        }
        return b[a[rt].l] + tmp;
    }
    pushdown(rt);
    int res = 0;
    int m = a[rt].mid();
    if (pos <= m) res = query(pos,rt<<1);
    else res = query(pos,rt<<1|1);
    return res;
}
int main(){
    //freopen("din.txt","r",stdin);
    int i,n,m;
    int op,x,y,c,k;
    init();
    while (~scanf("%d",&n)){
        for (i = 1; i <= n; ++i) scanf("%d",&b[i]);
        build(1,n,1);
        scanf("%d",&m);
        while (m--){
            scanf("%d",&op);
            if (op == 2){
                scanf("%d",&x);
                printf("%d\n",query(x,1));
            }
            else{
                scanf("%d%d%d%d",&x,&y,&k,&c);
                update(x,y,k,x%k,c,1);
            }
        }
    }
    return 0;
}

 

 

posted @ 2012-09-12 17:22  E_star  阅读(310)  评论(0编辑  收藏  举报