Problem C
发布时间: 2017年6月28日 11:38 最后更新: 2017年6月28日 16:38 时间限制: 1000ms 内存限制: 32M
给定一个长度为n的序列a1, a2, ..., an, 其中ai∈[1,10]
给出q个操作, 操作分为两种
对于形如1 x y的操作, 将ax改为y, 满足1≤x≤n, 1≤y≤10
对于形如2 x y z的操作, 输出下标介于[x,y]之间的元素中, 值为z的元素个数, 满足1≤x≤y≤n, 1≤z≤10
9×104≤n≤105, 9×104≤q≤105
第一行两个整数n, q, 意义如上所述。
接下来q行, 每行第一个数为opt, 如果opt=1, 后面紧跟两个数, 意义如上所述; 如果opt=2, 后面紧跟三个数, 意义如上所述。
对于每个操作3, 输出答案, 一行一个。
复制
8 3 3 1 4 1 5 9 2 6 2 1 8 2 1 2 2 2 1 8 2
1 2
非常简单的一道题目,开10个树状数组。
bitree[z]含义分别是值为z的位置分布的树状数组。
当把数字a[x]变成y的时候,要做两件事情
第一件:消除旧值的影响
add(a[x],x,-1);
第二件
a[x] = y
add(a[x],x,1)
增加对新的数的影响
查询区间[x,y]等于z的数的个数时候
直接在z对应的树状数组里求部分和就OK了
是不是非常简单
#include <cstdio>
const int MAX = 1e5+7;
int a[MAX];
int in[11][MAX];
int n,q;
inline int lowbit(int x){return x&(-x);
}
void add(int id,int pos,int val){while(pos <= n){in[id][pos] += val;pos += lowbit(pos);}
}
int getsum(int id,int pos){int res = 0;while(pos){res += in[id][pos];pos -= lowbit(pos);}return res;
}
int main(){scanf("%d%d",&n,&q);for(int i = 1;i <= n;i++){scanf("%d",&a[i]);add(a[i],i,1);}while(q--){int opt;scanf("%d",&opt);if(opt == 1){int x,y;scanf("%d%d",&x,&y);add(a[x],x,-1);a[x] = y;add(a[x],x,1);}else {int x,y,z;scanf("%d%d%d",&x,&y,&z);printf("%d\n",getsum(z,y) - getsum(z,x-1));}}}