HDU 4267 A Simple Problem with Integers

题目大意:

   两种操作:
         1.a,b,k,v      对于下标i, a<=i<=b ,(i-a)%k==0,num[i]+=v;

         2.a               求a位置数值的大小

解决方法:

    由于修改的区间不是连续的所以不太好处理,但是有题目中给出的k的范围很小,所以我们可以建立多个线段树进行维护。

    10>=k>=0 所以建立55个线段树,tree[55][maxn],并且做好标志数组vis[k][j],其表示i%k==j的标记为多少,i代表当前位置。

    (i-a)%k==0 等价于 i%k=a%k,所以求某个点就相当于求   for (int i=0;i<=10;i++)  sum+=tree[vis[k][a%k]][o];当然这仅仅是一个节点的处理,我们应该对经过的每个节点都进行上述处理,最终得到的sum就是结果。

    修改的操作类似与查询。

我的代码:

#include <algorithm>
#include <cstring>
#include <iostream>
#include <cstdio>
#define maxn 50050
using namespace std;
int vis[11][11];
int tree[maxn*3][55];
int num[maxn];
int build (int o,int L,int R){
  if (L==R){
    memset(tree[o],0,sizeof(tree[o]));
  }
  else {
    memset(tree[o],0,sizeof(tree[o]));
    int M=L+(R-L)/2;
    build (o*2,L,M);
    build (o*2+1,M+1,R);
  }
  return 0;
}
int y1,y2,k,d;
int changque(int o,int L,int R){
  if (y1<=L&&y2>=R){
    tree[o][vis[k][y1%k]]+=d;
  }
  else {
    int M=L+(R-L)/2;
    if (y1<=M) changque(o*2,L,M);
    if (y2>M) changque(o*2+1,M+1,R);
  }
  return 0;
}
int yy,_sum;
int query(int o,int L,int R){
  if (L==R&&L==yy){
    for (int i=1;i<=10;i++)
        _sum+=tree[o][vis[i][yy%i]];
  }
  else {
    for (int i=1;i<=10;i++)
        _sum+=tree[o][vis[i][yy%i]];
    int M=L+(R-L)/2;
    if (yy<=M) query(o*2,L,M);
    if (yy>M) query(o*2+1,M+1,R);
  }
  return 0;
}
int main (){
  //freopen("test.in","r",stdin);
  memset(vis,0,sizeof(vis));
  int totl=0;
  for (int i=1;i<=10;i++)
    for (int j=0;j<i;j++)
        vis[i][j]=totl++;
  int n,m;
  while (~scanf("%d",&n)){
    for (int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    build(1,1,n);
    scanf("%d",&m);
    for (int i=0;i<m;i++){
        int po; scanf("%d",&po);
        if (po==2) {
            scanf("%d",&yy);
            _sum=0;
            query(1,1,n);
            printf("%d\n",_sum+num[yy]);
        }
        else {
            scanf("%d%d%d%d",&y1,&y2,&k,&d);
            changque(1,1,n);
        }
    }
  }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值