zoukankan      html  css  js  c++  java
  • 二叉索引树,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:
    ",++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
    ",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
    ",ans);
    80     }
    81 
    82     return 0;
    83 }
    View Code
    
    
    
  • 相关阅读:
    javaapplicationWeb application setup on Ubuntu VPS
    内容中断随想录(risc cpu的那些事)
    算法线性编程珠玑读书笔记之----->使用线性算法求解连续子序列的最大和
    classnull100
    安装javaUbuntu下安装JDK1.6,并将之设为默认的JDK
    筛选实现C++实现筛选法
    调试设置移动端Web开发环境搭建实践
    路由器交换机[置顶] 路由器和交换机的综合实验⑵
    卡数字怀念的东西:魔方
    密码配置配置SSH免密码登陆
  • 原文地址:https://www.cnblogs.com/TreeDream/p/6296372.html
Copyright © 2011-2022 走看看