HDU 4267-Phage War-线段树

http://acm.hust.edu.cn/vjudge/problem/31829/origin


题意:n个数

q次操作

每次操作 1: 区间更新【a,b,k,c】  对区间【a,b】从a开始每k个加c

2:单点查询【x】 查询x的值



如果用树状数组,直接暴力 每个k,以及对应的x%k 的余数 也是【0到k-1】开一个树状数组,也就是开【k】【k】个数组,

当时sb了没想到,用线段树做,开不了二维,只能开k个线段树


通过把下标重新映射,相当于把 第二维组织到一个线段树里了。。。下标太恶心了。。233

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>


using namespace std;
const int N=51234;

int aa[N];
int sum[12][N*4];
int add[12][N*4];
int idx[12][12];
int num[12][12];


void pushDown(int i, int l, int r,int id)		//把i节点的延迟标记传递到左右儿子节点
{
    if(add[i] != 0)
    {
        int mid = (l + r) >> 1;
        add[id][i << 1] += add[id][i];
        sum[id][i << 1] += (mid - l + 1) * add[id][i];  //[l, mid]代表左儿子区间
        add[id][i << 1 | 1] += add[id][i];
        sum[id][i << 1 | 1] += (r - mid) * add[id][i];  //[mid + 1, r]代表右儿子区间
        add[id][i] = 0;
    }
}
void update(int i, int l, int r, int ql, int qr, int val,int id) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val,
{
    if(l > qr || ql > r)		//更新区间不在当前区间内
        return ;
    if(l >= ql && r <= qr)	//要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层
    {
        sum[id][i] += (r - l + 1) * val;
        add[id][i] += val;
        return ;
    }
    pushDown(i, l, r,id);			//如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去
    int mid = (l + r) >> 1;
    update(i << 1, l, mid, ql, qr, val,id);
    update(i << 1 | 1, mid + 1, r, ql, qr, val,id);
    sum[id][i] = sum[id][i << 1] + sum[id][i << 1 | 1];
}

int query(int i, int l, int r, int ql, int qr,int id)	 //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i
{
    if(l > qr || ql > r)
        return 0;
    if(l >= ql && r <= qr)
        return sum[id][i];
    pushDown(i, l, r,id);
    int mid =( l + r) >> 1;
    return query(i << 1, l, mid, ql, qr,id)
           + query(i << 1 | 1, mid + 1, r, ql, qr,id);

}
void init()
{
    memset(sum,0,sizeof sum);
    memset(add,0,sizeof add);
    memset(idx,0,sizeof idx);
    memset(num,0,sizeof num);
}
int  main()
{
    //freopen("input.txt","r",stdin);
    int n,q;
    while(scanf("%d",&n)!=EOF)
    {

        init();

        for (int i=1; i<=n; i++)
            scanf("%d",&aa[i]);
        for (int k=1; k<=10; k++)
        {
            num[k][0]=n/k;
            for (int i=1; i<=k-1; i++)
            {
                num[k][i]=n/k+((n%k>=i)?1:0);
            }
            idx[k][0]=num[k][0]?1:0;
            for (int i=1; i<=k-1; i++)
            {
                if (idx[k][i-1]==0)
                    idx[k][i]=1;
                else
                    idx[k][i]=idx[k][i-1]+num[k][i-1];
            }
        }
       /* for (int k=1; k<=10; k++)

        {
            for (int i=0; i<=k-1; i++)
            {
        printf("%d ",idx[k][i]);
            }
            printf("\n");
        }*/
        scanf("%d",&q);
        int op;
        int a,b,c,k;
        for (int i=1; i<=q; i++)
        {
            scanf("%d",&op);
            if (op==1)
            {

                scanf("%d%d%d%d",&a,&b,&k,&c);
                int res=a%k;
                int len=(b-a)/k;
                int index=idx[k][res]+a/k;
                if (a%k==0)index--;
                //if (!len ) len++;
              //  printf("your inval : (%d,%d)\n",index,index+len-1);
                update(1,1,n,index,index+len,c,k);

            }
            else
            {
                scanf("%d",&a);
                int ans=0;
                for (int j=1; j<=10; j++)
                {
                    int index=idx[j][a%j]+a/j;
                    if (a%j==0)index--;
                    ans+= query(1,1,n,index,index,j);
                }
                printf("%d\n",ans+aa[a]);
            }
        }


    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值