BOJ 451 田田的算术题

来源:互联网 发布:苹果为什么叫蜂窝网络 编辑:程序博客网 时间:2024/04/28 17:12

题意:给出一个数列。有两个操作:1.将给定范围内的项按照顺序加上一个等差数列的项。2.求出给定范围的数列项的和。

思路1:区间更改和区间求和的操作,很容易想到了线段树。由于等差数列满足可加性(即对相同范围内的数进行两次操作1,可以看做一次操作1的和),所以必定可以用线段树。

代码如下:

#include <bits/stdc++.h> using namespace std; template<class T>inline bool read(T &n){    T x = 0, tmp = 1; char c = getchar();    while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();    if (c == EOF) return false;    if (c == '-') c = getchar(), tmp = -1;    while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar();    n = x*tmp;    return true;} template <class T>inline void write(T n) {    if (n < 0) {        putchar('-');        n = -n;    }    int len = 0, data[20];    while (n) {        data[len++] = n % 10;        n /= 10;    }    if (!len) data[len++] = 0;    while (len--) putchar(data[len] + 48);}  typedef long long LL; const int MAXN = 101000; long long a[MAXN];int T, M, N, Q, l, r, x, d; struct interval{    int left, right, mid;    long long sum, delta, x;    bool lazy;}; struct SegmentTree{    static const int MAX = 8 * 101000;    interval node[MAX];     inline int lson(int n){ return n << 1; }    inline int rson(int n){ return (n << 1) | 1; }     void build(int l, int r, int n){        int m = (l + r) / 2;        node[n].left = l;        node[n].right = r;        node[n].mid = m;        node[n].sum = node[n].delta = node[n].x = 0LL;        node[n].lazy = false;         if (l == r){            node[n].sum = a[l];            return;        }        build(l, m, lson(n));        build(m + 1, r, rson(n));        node[n].sum += node[lson(n)].sum + node[rson(n)].sum;    }     void pushdown(int n){        if (node[n].left == node[n].right){            node[n].lazy = false;            return;        }         //printf("[%d %d]",node[n].left,node[n].right);         int l = lson(n);        node[l].lazy = true;        node[l].delta += node[n].delta;        node[l].x += node[n].x;        long long n1 = node[n].mid - node[n].left + 1;        node[l].sum += node[n].x * n1 + n1 * (n1 - 1) / 2 * node[n].delta;         //printf("lson: %lld ",node[l].sum);         int r = rson(n);        node[r].lazy = true;        node[r].delta += node[n].delta;        long long a1 = node[n].x + (node[n].mid - node[n].left + 1) * node[n].delta;        node[r].x += a1;        long long n2 = node[n].right - node[n].mid;        node[r].sum += a1 * n2 + n2 * (n2 - 1) / 2 * node[n].delta;         //printf("rson: %lld\n",node[r].sum);          node[n].lazy = false;        node[n].delta = node[n].x = 0LL;    }    long long sum(int l, int r, int n){        if(node[n].left == node[n].right)            return node[n].sum;        if(l <= node[n].left && node[n].right <= r)            return node[n].sum;         if(node[n].lazy)            pushdown(n);         long long ans = 0LL;         if (l <= node[n].mid)            ans += sum(l, r, lson(n));        if (r > node[n].mid)            ans += sum(l, r, rson(n));         return ans;    }    void modify(int l, int r, long long x, long long d, int n){        if(node[n].left == node[n].right){            node[n].sum += x;            return;        }         if (l <= node[n].left && node[n].right <= r){            node[n].lazy = true;            node[n].delta += d;            node[n].x += x;            long long n1 = r - l + 1;            node[n].sum += n1 * x + n1 *(n1 - 1) / 2 * d;             //printf("m: %d %d\n",l,r);            return;        }        if(node[n].lazy)            pushdown(n);         long long nn = r - l + 1;        node[n].sum += nn * x + nn * (nn - 1) / 2 * d;         if (r <= node[n].mid)            modify(l, r, x, d, lson(n));        else if (l > node[n].mid)            modify(l, r, x, d, rson(n));        else{            modify(l, node[n].mid, x, d, lson(n));            modify(node[n].mid + 1, r, x + (node[n].mid - l + 1) * d, d, rson(n));        }    }}; SegmentTree s;  int main(void){    //freopen("input.txt", "r", stdin);    //freopen("out.txt", "w", stdout);    read(T);    while (T--){        read(N), read(M);        for (int i = 1; i <= N; ++i)            read(a[i]);        s.build(1, N, 1);        for (int i = 0; i < M; ++i){            read(Q), read(l), read(r);            if (Q == 2)                write(s.sum(l, r, 1)),puts("");            else{                read(x), read(d);                s.modify(l, r, x, d, 1);            }        }    }    return 0;}


思路二:由于时限是10s,可以利用复杂度为n√n的块状数组。

              每个块状数组维护整体的和,和数组内所有元素对等差数列的加减(同样具有可加性)。

              如果查询或者修改区间有部分无法完全包含在块状数组中,则暴力的求和和更改。

              注意对数组大小的选择。过大过小都不合适。

代码如下:

#include <bits/stdc++.h> using namespace std; template<class T>inline bool read(T &n){    T x = 0, tmp = 1; char c = getchar();    while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();    if (c == EOF) return false;    if (c == '-') c = getchar(), tmp = -1;    while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar();    n = x*tmp;    return true;} template <class T>inline void write(T n) {    if (n < 0) {        putchar('-');        n = -n;    }    int len = 0, data[20];    while (n) {        data[len++] = n % 10;        n /= 10;    }    if (!len) data[len++] = 0;    while (len--) putchar(data[len] + 48);}  const int B = 250;const int MAX = 100100;int T,M,N,Q;int l,r,x,d; long long a[MAX]; struct buc{    long long sum;    long long d,x;    void clear(){        sum = d = x = 0LL;    }} bucket[MAX / B]; long long getsum(int l, int r){    long long ans = 0;    while(l < r && l % B != 0){        int id = l / B;        int pos = l - id * B;        ans += a[l] + bucket[id].x + pos * bucket[id].d;        l++;    }    while(l < r && r % B != 0){        r--;        int id = r / B;        int pos = r - id * B;        ans += a[r] + bucket[id].x + pos * bucket[id].d;    }    while(l < r){        int id = l / B;        ans += bucket[id].sum;        l += B;    }    return ans;} void update(int l,int r,long long x,long long d){    int cnt = 0;    while(l < r && l % B != 0){        int id = l / B;        long long aa = x + cnt * d;        a[l] += aa;        bucket[id].sum += aa;        cnt++,l++;    }    while(l + B < r){        int id = l / B;        bucket[id].sum += B * (x + cnt * d) + B *(B - 1) / 2 * d ;        bucket[id].x += x + cnt * d;        bucket[id].d += d;        l += B,cnt += B;    }    while(l < r){        int id = l / B;        long long aa = x + cnt * d;        a[l] += aa;        bucket[id].sum += aa;        cnt++,l++;    }} int main(void){    //freopen("input.txt","r",stdin);    //freopen("out.txt","w",stdout);    read(T);    while(T--){        read(N),read(M);        for(int i = 0 ; i < N / B + 1; i++)            bucket[i].clear();        for(int i = 0 ; i< N; ++i)            read(a[i]);        for(int i = 0 ; i< N; ++i){            int id = i / B;            bucket[id].sum += a[i];        }        for(int i = 0; i< M; ++i){            read(Q);            if(Q == 2){                read(l),read(r);                printf("%lld\n",getsum(l-1,r));            }            else{                read(l),read(r),read(x),read(d);                update(l-1,r,(long long)x,(long long)d);            }        }    }    return 0;}


0 0
原创粉丝点击