//目录

二叉索引树,LA2191,LA5902,LA4329

利用了二进制,二分的思想的一个很巧妙的数据结构,一个lowbit(x):二进制表示下的最右边的一个1开始对应的数值。

那么如果一个节点的为x左孩子,父亲节点就是 x + lowbit(x),如果是右孩子,父亲节点是 x-lowbit(x);

图中白条部分就是辅助数组C对应的最底下的和。

1、那么一个前缀和有是怎样的呢?

  就是从最底下开始,边往上走,边往左走。

2、修改单点呢?

  从最底下开始,边往上走,边往下走。

 

LA2191:

题目链接:https://vjudge.net/contest/147973#problem/A

题意:

先给出一个数组,然后有两个操作

S x y 把第x个数改成y

M x y计算x~y个数的和

Source Code:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 inline int lowbit(int x)
 6 {
 7     return x&-x;
 8 }
 9 
10 struct FenwickTree
11 {
12     int n;
13     vector<int> C;
14 
15     void resize(int n)
16     {
17         this->n = n;
18         C.resize(n+10);
19     }
20     void clear()
21     {
22         fill(C.begin(), C.end(), 0);
23     }
24 
25     // 计算A[1]+A[2]+...+A[x] (x<=n)
26     int sum(int x)
27     {
28         int ret = 0;
29         while(x > 0)
30         {
31             ret += C[x];
32             x -= lowbit(x);
33         }
34         return ret;
35     }
36 
37     // A[x] += d (1<=x<=n)
38     void add(int x, int d)
39     {
40         while(x <= n)
41         {
42             C[x] += d;
43             x += lowbit(x);
44         }
45     }
46 };
47 
48 FenwickTree f;
49 const int maxn = 200000+5;
50 int a[maxn];
51 
52 int main()
53 {
54    // freopen("in.txt","r",stdin);
55     int n;
56     int cases = 0;
57     while(scanf("%d",&n),n)
58     {
59         if(cases>0) puts("");
60         printf("Case %d:\n",++cases);
61         f.resize(n);
62         f.clear();
63         for(int i=1; i<=n; i++)
64         {
65             scanf("%d",&a[i]);
66             f.add(i,a[i]);
67         }
68 
69         char op[5];
70         while(scanf("%s",op)!=EOF)
71         {
72             if(!strcmp(op,"END"))
73                 break;
74             if(op[0]=='M')
75             {
76                 int x,y;
77                 scanf("%d%d",&x,&y);
78                 printf("%d\n",f.sum(y)-f.sum(x-1));
79             }
80             if(op[0]=='S')
81             {
82                 int x,y;
83                 scanf("%d%d",&x,&y);
84                 int add = y - a[x];
85                 a[x] = y;
86                 f.add(x,add);
87             }
88         }
89     }
90 
91     return 0;
92 }
View Code

 

LA5902:

题目链接:https://vjudge.net/contest/147973#problem/B

题意:

XXX喜欢看电影,他有好多好多的影碟,每个影碟都有个独立的编号。开始是从下往上影碟的顺序是n~1,他每次拿出影碟的时候,你需要输出压在该影碟上的有几个。(拿出后其他影碟顺序不变)看完影碟后,XXX会把影碟放在最上面。

分析:

把每个影碟放到一个考后的位置,这个位置有影碟,那么这里就是 1,否则是 0 ,每次询问,就是这个影碟所在的位置之前的前缀和,

把他放到前面去,当前位置置为 0 ,top 的位置 加 1,注意要记录每个影碟的所在位置。

Source Code:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 
 6 inline int lowbit(int x)
 7 {
 8     return x&-x;
 9 }
10 
11 struct FenwickTree
12 {
13     int n;
14     vector<int> C;
15 
16     void resize(int n)
17     {
18         this->n = n;
19         C.resize(n);
20     }
21     void clear()
22     {
23         fill(C.begin(), C.end(), 0);
24     }
25 
26     // 计算A[1]+A[2]+...+A[x] (x<=n)
27     int sum(int x)
28     {
29         int ret = 0;
30         while(x > 0)
31         {
32             ret += C[x];
33             x -= lowbit(x);
34         }
35         return ret;
36     }
37 
38     // A[x] += d (1<=x<=n)
39     void add(int x, int d)
40     {
41         while(x <= n)
42         {
43             C[x] += d;
44             x += lowbit(x);
45         }
46     }
47 };
48 
49 FenwickTree f;
50 const int maxn = 100000+5;
51 int pos[maxn];
52 
53 
54 int main()
55 {
56     //freopen("in.txt","r",stdin);
57     //freopen("out.txt","w",stdout);
58     int t;
59     scanf("%d",&t);
60 
61     while(t--)
62     {
63         int n,q;
64         scanf("%d%d",&n,&q);
65         f.resize(maxn*2);
66         f.clear();
67 
68         for(int i=1; i<=n; i++)
69         {
70             f.add(maxn+i,1);
71             pos[i] = maxn+i;
72         }
73 
74         int top = maxn;
75         while(q--)
76         {
77             int x;
78             scanf("%d",&x);
79             int tmp = pos[x];
80             if(q!=0)
81                 printf("%d ",f.sum(tmp-1));
82             else printf("%d",f.sum(tmp-1));
83             f.add(tmp,-1);
84             f.add(top--,1);
85             pos[x] = top + 1;
86         }
87         puts("");
88     }
89     return 0;
90 }
View Code

 

LA4329

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=26&page=show_problem&problem=2330

题意:

一条大街上住着n个乒乓球爱好者,经常组织比赛。每个人都有一个技能值ai,每场比赛需要3个人:两名选手和一名裁判。规定裁判位置必须在两个选手的中间,而且技能值也必须在两个选手的中间,问一共能组织多少种比赛。

分析:

和上题类似,每个技能值有的话为 1 ,否则为 0 ,每一个点都可以做裁判,那么他能组织多少场比赛?

a1~ai-1 有 ci个比 ai 小,ai+1~an有di个比他小,乘法加法原理,ci(n-i-di) + di(i-ci-1)。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 
 6 inline int lowbit(int x) {
 7     return x&-x;
 8 }
 9 
10 struct FenwickTree {
11     int n;
12     vector<int> C;
13 
14     void resize(int n) {
15         this->n = n;
16         C.resize(n);
17     }
18 
19     void clear() {
20         fill(C.begin(),C.end(),0);
21     }
22 
23     //计算A[1] + A[2] + ... +A[n]
24     int sum(int x) {
25         int ret = 0;
26         while(x>0) {
27             ret +=C[x];
28             x -=lowbit(x);
29         }
30         return ret;
31     }
32 
33     // A[x] +=d;
34     void add(int x,int d) {
35         while(x<=n) {
36             C[x] +=d;
37             x +=lowbit(x);
38         }
39     }
40 };
41 
42 const int maxn = 20000 + 5;
43 int n;
44 int a[maxn];
45 FenwickTree f;
46 int c[maxn],d[maxn];
47 
48 int main()
49 {
50     int t;
51     scanf("%d",&t);
52     while(t--)
53     {
54         int maxa  = 0;
55         scanf("%d",&n);
56         for(int i=1;i<=n;i++) {
57             scanf("%d",&a[i]);
58             maxa = max(maxa,a[i]);
59         }
60 
61         f.resize(maxa);
62         f.clear();
63 
64         for(int i=1;i<=n;i++) {
65             f.add(a[i],1);
66             c[i] = f.sum(a[i]-1);
67         }
68 
69         f.clear();
70         for(int i=n;i>=1;i--) {
71             f.add(a[i],1);
72             d[i] = f.sum(a[i]-1);
73         }
74 
75         long long ans = 0;
76         for(int i=1;i<=n;i++) {
77             ans +=(long long)c[i]*(n-i-d[i]) + (long long)(i-c[i]-1)*d[i];
78         }
79         printf("%lld\n",ans);
80     }
81 
82     return 0;
83 }
View Code

 

 


 

posted @ 2017-01-18 13:02  小草的大树梦  阅读(280)  评论(0编辑  收藏  举报