6567: 清点人数 树状数组

发布时间 2023-05-31 21:54:04作者: CRt0729

描述

 

NK 中学组织同学们去五云山寨参加社会实践活动,按惯例要乘坐火车去。由于 NK 中学的学生很多,在火车开之前必须清点好人数。

初始时,火车上没有学生。当同学们开始上火车时,年级主任从第一节车厢出发走到最后一节车厢,每节车厢随时都有可能有同学上下。年级主任走到第 m 节车厢时,他想知道前 m 节车厢上一共有多少学生,但是他没有调头往回走的习惯。也就是说每次当他提问时,m 总会比前一次大。

 

输入

 

第一行两个整数 n,k,表示火车共有 n 节车厢以及 k 个事件。

接下来有 k 行,按时间先后给出 k 个事件,每行开头都有一个字母 A,B 或 C。

如果字母为 A,接下来是一个数 m,表示年级主任现在在第 m 节车厢;

如果字母为 B,接下来是两个数 m,p,表示在第 m 节车厢有 p 名学生上车;

如果字母为 C,接下来是两个数 m,p,表示在第 m 节车厢有 p 名学生下车。

学生总人数不会超过 105 。

对于 30% 的数据,1≤n,k≤104 ,至少有 3000 个 A;

对于 100% 的数据,1≤n≤5×105,1≤k≤105 ,至少有 3×104 个 A。

 

输出

 

对于每个 A ,输出一行,一个整数,表示年级主任的问题的答案。

 

样例输入

 

10 7
A 1
B 1 1
B 3 1
B 4 1
A 2
A 3
A 10

样例输出

 

0
1
2
3

 

思路:A是求m的前缀和,B是在m点加上p,C是在m点减去p

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+10,inf = 0x3f3f3f3f;
int c[N];
int n,k,v,m,p;
char op[2];
int lowbit(int x)
{
    return x&(-x);
}
void updata(int x,int v) //在x点上加v
{
    while(x<=n)
    {
        c[x]+=v;
        x+=lowbit(x);
    }
} 
int sum(int x)
{
    int res = 0;
    while(x>0)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=k;i++)
    {
        scanf("%s",op);
        //cout<<op<<endl
        if(op[0]=='A')
        {
            scanf("%d",&m);
            printf("%d\n",sum(m));
        }
        else if(op[0]=='B')
        {
            scanf("%d%d",&m,&p);
            updata(m,p);
        }
        else
        {
            scanf("%d%d",&m,&p);
            updata(m,-p);
        }
    }
     return 0;
}