Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood

   PDF (English) Statistics Forum
Time Limit: 1 second(s) Memory Limit: 64 MB

Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another trick. He keeps n sacks where he keeps this money. The sacks are numbered from 0 to n-1.

Now each time he can he can do one of the three tasks.

1)                  Give all the money of the ith sack to the poor, leaving the sack empty.

2)                  Add new amount (given in input) in the ith sack.

3)                  Find the total amount of money from ith sack to jth sack.

Since he is not a programmer, he seeks your help.

Input

Input starts with an integer T (≤ 5), denoting the number of test cases.

Each case contains two integers n (1 ≤ n ≤ 105) and q (1 ≤ q ≤ 50000). The next line contains n space separated integers in the range [0, 1000]. The ith integer denotes the initial amount of money in the ith sack (0 ≤ i < n).

Each of the next q lines contains a task in one of the following form:

1 i        Give all the money of the ith (0 ≤ i < n) sack to the poor.

2 i v     Add money v (1 ≤ v ≤ 1000) to the ith (0 ≤ i < n) sack.

3 i j      Find the total amount of money from ith sack to jth sack (0 ≤ i ≤ j < n).

Output

For each test case, print the case number first. If the query type is 1, then print the amount of money given to the poor. If the query type is 3, print the total amount from ith to jth sack.

Sample Input

Output for Sample Input


1

5 6

3 2 1 4 5

1 4

2 3 4

3 0 3

1 2

3 0 4

1 1


Case 1:

5

14

1

13

2

Notes

Dataset is huge, use faster I/O methods.

题解:简单的树状数组;线段树也很简单;

1 i        Give all the money of the ith (0 ≤ i < n) sack to the poor.

2 i v     Add money v (1 ≤ v ≤ 1000) to the ith (0 ≤ i < n) sack.

3 i j      Find the total amount of money from ith sack to jth sack (0 ≤ i ≤ j < n).

树状数组代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
#define mem(x,y) memset(x,y,sizeof(x))
#define SI(x) scanf("%d",&x)
#define PI(x) printf("%d",x)
typedef long long LL;
const int MAXN=1e5+100;
int tree[MAXN];
int lowbit(int x){return x&(-x);}
void add(int x,int v){
    while(x<MAXN){
        tree[x]+=v;
        x+=lowbit(x);
    }
}
int SUM(int x){
    int sum=0;
    while(x>0){
        sum+=tree[x];
        x-=lowbit(x);
    }
    return sum;
}
int main(){
    int T,kase=0;
    int N,M;
    SI(T);
    while(T--){
        SI(N);SI(M);
        mem(tree,0);
        for(int i=1;i<=N;i++){
            int temp;
            SI(temp);
            add(i,temp);
        }
        printf("Case %d:\n",++kase);
        while(M--){
            int q,a,b,ans;
            SI(q);
            if(q==1){
                SI(a);a++;
                ans=SUM(a)-SUM(a-1);
                add(a,-ans);
                printf("%d\n",ans);
            }
            else if(q==2){
                SI(a);SI(b);
                a++;
                add(a,b);
            }
            else{
                SI(a);SI(b);a++;b++;
                printf("%d\n",SUM(b)-SUM(a-1));
            }
        }
    }
    return 0;
}

线段树:

/*
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
#define mem(x,y) memset(x,y,sizeof(x))
#define SI(x) scanf("%d",&x)
#define PI(x) printf("%d",x)
typedef long long LL;
const int MAXN=1e5+100;
int tree[MAXN];
int lowbit(int x){return x&(-x);}
void add(int x,int v){
    while(x<MAXN){
        tree[x]+=v;
        x+=lowbit(x);
    }
}
int SUM(int x){
    int sum=0;
    while(x>0){
        sum+=tree[x];
        x-=lowbit(x);
    }
    return sum;
}
int main(){
    int T,kase=0;
    int N,M;
    SI(T);
    while(T--){
        SI(N);SI(M);
        mem(tree,0);
        for(int i=1;i<=N;i++){
            int temp;
            SI(temp);
            add(i,temp);
        }
        printf("Case %d:\n",++kase);
        while(M--){
            int q,a,b,ans;
            SI(q);
            if(q==1){
                SI(a);a++;
                ans=SUM(a)-SUM(a-1);
                add(a,-ans);
                printf("%d\n",ans);
            }
            else if(q==2){
                SI(a);SI(b);
                a++;
                add(a,b);
            }
            else{
                SI(a);SI(b);a++;b++;
                printf("%d\n",SUM(b)-SUM(a-1));
            }
        }
    }
    return 0;
}
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
#define mem(x,y) memset(x,y,sizeof(x))
#define SI(x) scanf("%d",&x)
#define PI(x) printf("%d",x)
typedef long long LL;
const int MAXN=1e5+100;
#define ll root<<1
#define rr root<<1|1
#define lson ll,l,mid
#define rson rr,mid+1,r
int tree[MAXN<<2];
int ans;
void pushup(int root){
    tree[root]=tree[ll]+tree[rr];
}
void build(int root,int l,int r){
    int mid=(l+r)>>1;
    if(l==r){
        SI(tree[root]);
        return;
    }
    build(lson);build(rson);
    pushup(root);
}
void update(int root,int l,int r,int A,int B){
    if(l==A&&r==A){
        tree[root]+=B;
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=A)update(lson,A,B);
    else update(rson,A,B);
    pushup(root);
}
void query(int root,int l,int r,int A,int B){
    if(l>=A&&r<=B){
        ans+=tree[root];
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=A)query(lson,A,B);
    if(mid<B)query(rson,A,B);
}
int main(){
    int T;
    int N,M,kase=0;
    SI(T);
    while(T--){
        SI(N);SI(M);
        build(1,1,N);
        printf("Case %d:\n",++kase);
        while(M--){
            int q,a,b;
            SI(q);
            if(q==1){
                SI(a);a++;
                ans=0;
                query(1,1,N,a,a);
                printf("%d\n",ans);
                update(1,1,N,a,-ans);
            }
            else if(q==2){
                SI(a);SI(b);
                a++;
                update(1,1,N,a,b);
            }
            else{
                SI(a);SI(b);a++;b++;
                ans=0;
                query(1,1,N,a,b);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
时间: 2024-10-14 05:35:28

Curious Robin Hood(树状数组+线段树)的相关文章

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 1166 敌兵布阵 (树状数组&#183;线段树)

题意  中文 动态区间和问题   只会更新点  最基础的树状数组 线段树的应用 树状数组代码 #include <bits/stdc++.h> using namespace std; const int N = 50005; int c[N], n, m; void add(int p, int x) { while(p <= n) c[p] += x, p += p & -p; } int getSum(int p) { int ret = 0; while(p > 0

士兵杀敌(四)(树状数组+线段树)

士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧. 假设起始时所有人的军功都是0. 输入

Color the ball(树状数组+线段树)

Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 3   Accepted Submission(s) : 1 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b

Codeforces Round #225 (Div. 1) C 树状数组 || 线段树

看到这题很开心啊,有印象跟以前做过的很像,貌似最近就做过一个,以时间戳为区间来建立树状数组,然后一开始我以为题意是,给x点加val,它以下的所有节点都加-val:所以一开始就以 加 和 减 建立了两个树状数组,最后 减去就是答案,写完发现跟案例对不上啊,读了题目也没发现读错了,对于那句话 我理解错了,后来看了 这个: http://blog.csdn.net/keshuai19940722/article/details/18967661 仔细看看处理部分,我还以为分奇偶性有规律呢,后来才发现读

HDU 4417 Super Mario (树状数组/线段树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble agai

BZOJ 3211 花神游历各国 树状数组(线段树)+优化

题意:给你一段区间,然后每个点的初始值都告诉你,现有两种操作,一种是给你一个小区间的左右端点,之后把这个区间内的所有值都开根号,另一种就是区间求值. 方法:树状数组维护求和,巧妙开根号.(线段树) 解析:这道是某次考试考的题- -.当时也没想到快的开根号方法,暴力开根号好像70分吧. 首先要明确一个事情:被开根号的数最大是109,而109开几次会开到1呢?用计算器算一下发现5次就将这个最大的数开到1了,而1开根号怎么开都是1,所以如果再对其进行开根号操作,仅仅是无用的浪费时间了.所以怎么维护这种