bzoj4397【Usaco2015 Dec】Breed Counting(前缀和、树状数组)

题目描述

Farmer John's N cows, conveniently numbered 1…N, are all standing in a row (they seem to do so often that it now takes very little prompting from Farmer John to line them up). Each cow has a breed ID: 1 for Holsteins, 2 for Guernseys, and 3 for Jerseys. Farmer John would like your help counting the number of cows of each breed that lie within certain intervals of the ordering.

输入

The first line of input contains N and Q (1≤N≤100,000, 1≤Q≤100,000).

The next N lines contain an integer that is either 1, 2, or 3, giving the breed ID of a single cow in the ordering.

The next Q lines describe a query in the form of two integers a,b (a≤b).

输出

For each of the Q queries (a,b), print a line containing three numbers: the number of cows numbered a…b that are Holsteins (breed 1), Guernseys (breed 2), and Jerseys (breed 3).

样例输入

6 3
2
1
1
3
2
1
1 6
3 3
2 4

样例输出

3 2 1
1 0 0
2 0 1

  题目的意思就是给你n个牛槽的位置(编号从1到n),q是查询次数,每个牛槽里有一只奶牛,奶牛有三个品种(分别为1,2,3),告诉你每个牛槽中奶牛的种类。
给你q个查询的区间,让你输出每个查询区间内三种奶牛分别有多少头。
  这个题我写了两种解法,一种是前缀和数组(a[i]表示从1到i一共有多少头X品种牛),还有一种解法就是写树状数组。但是从运行时间上来看,肯定是前缀和要比树状数组要快。
前缀和数组代码如下:
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int sum[3][100050];
 4 int main()
 5 {
 6     int n,q;
 7     //freopen("de.txt","r",stdin);
 8     while (~scanf("%d%d",&n,&q))
 9     {
10         memset(sum,0,sizeof sum);
11         for (int i=1;i<=n;++i)
12         {
13             for (int j=0;j<3;++j)
14             sum[j][i]=sum[j][i-1];
15             int x;
16             scanf("%d",&x);
17             sum[x-1][i]++;
18         }
19         for (int i=0;i<q;++i)
20         {
21             int x,y;
22             scanf("%d%d",&x,&y);
23             printf("%d %d %d
",sum[0][y]-sum[0][x-1],sum[1][y]-sum[1][x-1],sum[2][y]-sum[2][x-1]);
24         }
25     }
26  
27 }
   Time:100 ms
    Memory:2868 kb


树状数组代码如下:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <algorithm>
 6 #include <string>
 7 using namespace std;
 8 #define maxn 111111
 9 int sum[maxn<<2][3],sum2[maxn<<2],sum3[maxn<<2];
10 void pushup (int rt,int num)
11 {
12     sum[rt][num]=sum[rt<<1][num]+sum[rt<<1|1][num];
13 }
14  
15 void update (int p,int l,int r,int rt,int num)
16 {
17     if (l==r)
18     {
19         sum[rt][num]++;
20         return;
21     }
22     int m=(l+r)>>1;
23     if (p<=m)
24     update(p,l,m,rt<<1,num);
25     else
26     update(p,m+1,r,rt<<1|1,num);
27     pushup(rt,num);
28 }
29 int query (int ll,int rr,int l,int r,int rt,int num)
30 {
31     if (ll<=l&&rr>=r)
32     return sum[rt][num];
33  
34     int ret=0;
35     int m=(l+r)>>1;
36  
37     if (ll<=m)
38     ret+=query(ll,rr,l,m,rt<<1,num);
39     if (rr>m)
40     ret+=query(ll,rr,m+1,r,rt<<1|1,num);
41     return ret;
42 }
43 int main()
44 {
45     int n,q;
46     //freopen("de.txt","r",stdin);
47     while (~scanf("%d%d",&n,&q))
48     {
49         memset(sum,0,sizeof sum);
50         for (int i=1;i<=n;++i)
51         {
52             int x;
53             scanf("%d",&x);
54             update(i,1,n,1,x-1);
55         }
56         for (int i=0;i<q;++i)
57         {
58             int x,y;
59             scanf("%d%d",&x,&y);
60             printf("%d ",query(x,y,1,n,1,0));
61             printf("%d ",query(x,y,1,n,1,1));
62             printf("%d
",query(x,y,1,n,1,2));
63         }
64     }
65     return 0;
66 }
67     Time:360 ms
68     Memory:10376 kb

PS:这个树状数组的模板是我hdu1166这个题的模板改的。

 
原文地址:https://www.cnblogs.com/agenthtb/p/5759528.html