http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1003&ojid=0&cid=601&hide=0
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
Input
每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。
Output
每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
Sample Input
31 12 23 331 11 21 30
Sample Output
1 1 13 2 1
思路:这是一道插线问点的题:
树状数组无非有两种考法:
1.修改一段区间的值,查找的是某个位上的值。要向上统计,向下修改;即插线问点。
2.修改某个位置上的值,查找的是一段区间的和。要向上修改,向下统计;即插点问线。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=100001; int d[maxn]; int n; int lowbit(int i) { return i&(-i); } void update(int i,int x) { while(i>0) { d[i]+=x; i-=lowbit(i); } } int get_sum(int i) { int ret=0; while(i<=n) { ret+=d[i]; i+=lowbit(i); } return ret; } int main() { int a ,b; while(scanf("%d",&n),n) { memset(d,0,sizeof(d)); for(int i=1;i<=n;i++) { scanf("%d %d",&a,&b); update(b,1); update(a-1,-1); } for(i=1;i<n;i++) printf("%d ",get_sum(i)); printf("%d\n",get_sum(n)); } return 0; }
http://59.69.128.200/JudgeOnline/problem.php?pid=116
代码:
#include<iostream> #include<cstdio> using namespace std; int N; int aa[1000010]; int lowbit(int i) {return i&(-i);} void g(int n,int m) { while(n<=N) { aa[n]+=m; n+=lowbit(n); } } int f(int n) { int sum=0; while(n>0) {sum+=aa[n]; n-=lowbit(n); } return sum; } int main() { int k; scanf("%d%d",&N,&k); for(int i=1;i<=N;++i) { int t; scanf("%d",&t); g(i,t); } while(k--) { char a[10]; scanf("%s",a); int x,y; scanf("%d%d",&x,&y); if(a[0]=='A') g(x,y); else printf("%d\n",f(y)-f(x-1)); }return 0; }