[cdoj 1344]树状数组区间加等差数列

题目链接:http://acm.uestc.edu.cn/#/problem/show/1344

区间加等差数列本质上就是区间修改区间查询,本来想用线段树做,结果这个题就是卡空间和时间……不得已学了区间修改区间查询的树状数组。

#include<bits/stdc++.h>
using namespace std;

const int maxn=1000005;
const int md=772002+233;
int a[maxn];
int N;
int tree[maxn];
int tree2[maxn];

int lowbit(int x)
{
    return x&-x;
}
void add(int tree[],int k,int x)
{
    while (k<=N)
    {
        tree[k]=(tree[k]+x)%md;
        k+=lowbit(k);
    }
}
int query(int tree[],int k)
{
    int res=0;
    while (k)
    {
        res=(res+tree[k])%md;
        k-=lowbit(k);
    }
    return res;
}
void add(int l,int r,int x)
{
    add(tree,l,x);
    add(tree,r+1,((-x)%md+md)%md);
    add(tree2,l,1ll*(l-1)*x%md);
    add(tree2,r+1,(1ll*r*(-x)%md+md)%md);
}
int querysum(int k)
{
    return ((1ll*query(tree,k)*k%md-query(tree2,k))%md+md)%md;
}
void addad(int l,int r,int a0,int d)
{
    add(l,l,a0);
    if (l+1<=r) add(l+1,r,d);
    add(r+1,r+1,(-(a0+1ll*(r-l)*d%md)%md+md)%md);
}
int queryad(int k)
{
    return querysum(k);
}
void init(int n)
{
    N=n+2;
    for (int i=0;i<=N;i++) tree[i]=tree2[i]=0;
}

int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]%=md;
    init(n);
    while (q--)
    {
        int op;
        scanf("%d",&op);
        if (op==1)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int l=x;
            int r=min(x+y-1,n);
            addad(l,r,y,-1);
        }
        else
        {
            int x;
            scanf("%d",&x);
            printf("%d\n",(a[x]+queryad(x))%md);
        }
    }
    return 0;
}

 

posted @ 2017-07-23 20:15  ACMsong  阅读(831)  评论(0编辑  收藏  举报