CodeChef Chef and Churu Problem

Chef and Churu Problem Code: FNCS
Add problem to Todo list
Tweet
链接

All submissions for this problem are available.
Read problems statements in Mandarin Chinese and Russian.
Chef has recently learnt Function and Addition. He is too exited to teach this to his friend Churu. Chef and Churu are very fast friends, they share their knowledge whenever they meet. Chef use to give a lot of exercises after he teaches some concept to Churu.

Chef has an array of N numbers. He also has N functions. Each function will return the sum of all numbers in the array from Li to Ri. So Chef asks churu a lot of queries which are of two types.
Type 1: Change the xth element of the array to y.
Type 2: Return the sum of all functions from m to n.

Now Churu has started to solve, but Chef realize that it is tough for him to decide whether Churu is correct or not. So he needs your help , will you help him out ?
Input Format
First Line is the size of the array i.e. N
Next Line contains N space separated numbers Ai denoting the array
Next N line follows denoting Li and Ri for each functions.
Next Line contains an integer Q , number of queries to follow.
Next Q line follows , each line containing a query of Type 1 or Type 2.
1 x y : denotes a type 1 query,where x and y are integers
2 m n : denotes a type 2 query where m and n are integers
Output Format
For each query of type 2 , output as asked above.
Constraints
1 ≤ N ≤ 105
1 ≤ Ai ≤ 109
1 ≤ Li ≤ N
Li ≤ Ri ≤ N
1 ≤ Q ≤ 105
1 ≤ x ≤ N
1 ≤ y ≤ 109
1 ≤ m ≤ N
m ≤ n ≤ N
Subtask
Subtask 1: N ≤ 1000 , Q ≤ 1000 , 10 points
Subtask 2: R-L ≤ 10 , all x will be distinct ,10 points
Subtask 3: Refer to constraints above , 80 points
Sample Input
5
1 2 3 4 5
1 3
2 5
4 5
3 5
1 2
4
2 1 4
1 3 7
2 1 4
2 3 5
Sample Output
41
53
28
Explanation
Functions values initially :
F[1] = 1+ 2 + 3 = 6
F[2] = 2 + 3 + 4 + 5 = 14
F[3] = 4+5 = 9
F[4] = 3+4+5 = 12
F[5] = 1+2 = 3
Query 1: F[1] + F[2] + F[3] + F[4] = 41
After Update , the Functions are :
F[1] = 10 , F[2] = 18 , F[3] = 9 , F[4] = 16 , F[5] = 3
Query 3: F[1] + F[2] + F[3] + F[4] = 53
Query 4: F[3]+F[4]+F[5] = 28

考完试,交了代码,闲的没事,想整点事,随便搜了个题解,用mjt的名字交了上去,80分,,,,叫我讲题。。。
没关系,有我在hold住全场,lrh说他见过原题,于是我就淡定的走上讲台:“对于考试,我们要合理的利用上厕所的时间,lrh在厕所告诉我他见过原题,然后。。。然后就请他讲吧。”哈哈,果断帅锅lrh。。

哈哈哈。。。

分析:分块+树状数组,,,每次查询的时候,中间完整的块,直接加进答案去,两端的用树状数组解决,还需要对N个函数进行分块,分块处理出每个块内,序列中第i个数被这个块内的函数覆盖的次数, 然后处理出每个块内函数的和,由于是单点更新,所以在维护每个块函数的和的时候是比较好维护的(因为已经知道了第i个数被这个块内的函数覆盖的次数),然后就是区间查询了,直接分块处理就好了。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define MAXN 100010
#define BLOCK 400
#define lowbit(x) (x & (-x))
using namespace std;
typedef long long LL;
int n,m,li[MAXN],ri[MAXN],a[MAXN];
LL Bit[MAXN],sumb[BLOCK];
int vis[BLOCK][MAXN],unic,Num;

inline void read(int &x) {
    x = 0; register char c = getchar(); int f = 1;
    while(c > '9' || c < '0') { c = getchar(); f = -1; }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } x *= f;
}

void Insert(int pos,int val) { for(; pos<=n; pos += lowbit(pos)) Bit[pos] += val; }
void UpDate(int x,int y) {
    Insert(x,y-a[x]);
    for(int i=1; i<=Num; ++i) sumb[i] += (LL) vis[i][x] * (y - a[x]);
    a[x] = y;
}

LL Get_Sum(int pos) {
    LL sum = 0;
    for(; pos; pos -= lowbit(pos)) sum += Bit[pos];
    return sum;
}

LL Query(int l,int r) {
    int lb = (l - 1) / unic + 1,rb = (r - 1) / unic + 1;LL Sum = 0;
    if(lb == rb) 
        for(int i=l; i<=r; ++i) Sum += Get_Sum(ri[i]) - Get_Sum(li[i] - 1);
    else  {
        for(int i=lb+1; i<=rb-1; ++i) Sum += sumb[i];
        for(int i=l; i<=lb*unic; ++i) Sum += Get_Sum(ri[i]) - Get_Sum(li[i] - 1);
        for(int i=(rb - 1)*unic+1; i<=r; ++i) Sum += Get_Sum(ri[i]) - Get_Sum(li[i] - 1);
    }
    return Sum;
}

int main(int argc,char *argv[]) {
    read(n);
    for(int i=1; i<=n; ++i) read(a[i]);
    for(int i=1; i<=n; ++i) read(li[i]),read(ri[i]);
    for(int i=1; i<=n; ++i) Insert(i,a[i]);
    int Now = 0;
    Num = unic = sqrt(n);
    if(unic * unic != n) Num ++;
    for(int i=1; i<=n; ++i) {
        if(i % unic == 1) ++Now;
        vis[Now][li[i]]++,vis[Now][ri[i] + 1]--;
    }
    for(int i=1; i<=Num; ++i)
        for(int j=1; j<=n; ++j) {
            vis[i][j] += vis[i][j-1];
            sumb[i] += (LL)vis[i][j] * a[j];
        }
    int opt,x,y; read(m);
    while(m--) {
        read(opt),read(x),read(y);
        if(opt == 1) UpDate(x,y);
        else printf("%lld\n",Query(x,y));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值