Ural 2062

来源:互联网 发布:2017科普知识网络竞赛 编辑:程序博客网 时间:2024/05/22 08:08

Time limit: 3.0 second

Memory limit: 128 MB

Description

During several decades, scientists from planet Nibiru are working to create an engine that would allow spacecrafts to fall into hyperspace and move there with superluminal velocity. To check whether their understanding of properties of hyperspace is right, scientists have developed the following experiment.

A chain of n particles is placed in hyperspace. Positions of particles in the chain are numbered from 1 to n. Initially, *i*th particle has charge ai.

According to the current theory, if particle number i got special radiation with power d, oscillations would spread by hyperspace and increase by d charge of particles with numbers i, 2*i*, 3*i* and so on (i.e. with numbers divisible by i).

Using a special device, scientists can direct the radiation of the same power at a segment of adjacent particles. For example, suppose that initially there were 6 particles with zero charges, and scientists have sent radiation with power five to particles with numbers 2 and 3. Then charge of 2nd, 3rd, and 4th particles will increase to five, and charge of 6th particle will increase to ten (the oscillations will reach it twice). Charge of other particles won’t change.

Charge of particles can’t change without impact of the device.

During the experiment, the scientists plan to perform actions of the following types:

  1. Measure current charge of the particle number i.
  2. Direct radiation with power d at particles with numbers from l to r inclusive.

Your program will be given a list of performed actions. For every action of the first type the program should output value of expected charge of the particle calculated in accordance with the current theory described above.

If the expected charges of the particles coincide with charges measured during the experiment, it will turn out that scientists’ understanding of hyperspace is right, and they will be able to start building of the hyperdrives. Then inhabitants of Nibiru will finally meet their brothers from Earth in just a few years!

Input

The first line contains a single integer n — number of particles (1n3×105).

The second line contains n integers a**i separated by spaces — initial charges of the particles (0ai106).

The third line contains a single integer q — number of actions in the experiment (1q3×105).

Each of the following q lines contain two or four integers — a description of the next action in one of the following formats:

  • 1 i — measure current charge of the particle number i (1 ≤ in).
  • 2 l r d — direct radiation with power d at particles with numbers from l to r inclusive (1lrn,0d106).

Output

For each query output the expected charge of the *i*th particle.

题意

给定 n 个数,每个数均有一个初值 a1,a2,...,an。之后有 q 个操作。操作分为两种:

  • 给定 1 i ——要求输出当前点 i 的值
  • 给定 2 l r d —— 将区间 [l, r] 内的每一点 k ,将 k, 2k, 3k, 4k, … 位置上的值都加上 d 。

分析

很显然,初始值不会对后续的操作产生任何影响,此处仅需要单独保存在一个数组中,在每次询问的最后加上初值就可以。

考虑到区间更新,单点查询的话,很容易能够想到套用树状数组的板。

但是,此处的区间更新显示不只是更新区间,区间内的点同时也会对其倍数点产生影响。如果考虑在更新的同时更新后续倍数点,复杂度显然无法满足条件。因此,对于2 l r d ,仅考虑更新区间 [l, r] 。单次操作复杂度为 O(logN)

由于上述无法处理区间更新带来的后续倍数点的更新,故在单点查询过程中必须对最后结果加以保证。我想到的方法是——每个点的更新对其倍数点产生影响,可以理解为每个点的值必须考虑其约数点对其的影响,故暴力寻找点的约数,并通过单点查询获取对当前值的贡献。单次操作复杂度O(logN×N)

虽然觉得这个代码是不可能过的,但是,抱着试一试的态度,果断Accepted

代码

#include<bits/stdc++.h>using namespace std;const int N = 1e6 + 10;int a[N];long long bin[N];inline int lowbit(int x){return x & -x;}long long sum(int x){    long long res = 0;    for(int i=x;i;i-=lowbit(i)) res += bin[i];    return res;}void add(int x,int w){    for(int i=x;i<N;i+=lowbit(i))   bin[i] += w;}void update(int x,int y,int w){    add(x,w);   add(y+1,-w);}int main(){    int n,q;    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    scanf("%d",&q);    for(int i=0,typ,l,r,val,x;i<q;i++)    {        scanf("%d",&typ);        if(typ == 2)        {            scanf("%d %d %d",&l,&r,&val);            update(l, r, val);        }        else        {            scanf("%d",&x);            long long ans = a[x];            int seq = sqrt(x+0.5);            for(int i=1;i<=seq;i++)            {                if(x % i == 0)                {                    ans += sum(i);                    if(i*i != x)                        ans += sum(x/i);                }            }            printf("%I64d\n",ans);        }    }}
0 0
原创粉丝点击