zoukankan      html  css  js  c++  java
  • cdoj841-休生伤杜景死惊开 (逆序数变形)【线段树 树状数组】

    http://acm.uestc.edu.cn/#/problem/show/841

    休生伤杜景死惊开

    Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
     

    陆伯言军陷八卦阵之中,分明只是一条直路,却怎的也走不到尽头。阵中尽是石堆,以某一石堆为参考,无论向走还是向右,总是会回到出发的石堆,最后幸得一黄姓老翁带路才得脱出。

    陆伯言逃离八卦阵后,来到山顶观察此阵,记从左往右第i堆石堆的高度为Ai,发现任何两堆较矮的石堆都能和它们之间的一座较高的石堆形成"八卦锁",将其中之人牢牢锁住,无从逃脱。

    根据石堆的情况,陆伯言大致计算了“八卦锁”的数量(即 Ai<Aj>Ak,i<j<k 的组合数),不禁心中一惊,对孔明惊为天人,遂放弃追击,收兵回吴。

    “有劳岳父了。” “为何将其放走?” “...一表人才,何必浪费于此。”

    Input

    第一行一个整数n,表示石堆堆数。

    接下来一行,n个整数,第i个数表示从左到右第i堆石堆的高度Ai。

    1≤n≤50000,1≤Ai≤32768

    Output

    一个整数,“八阵锁”的数目。

    Sample input and output

    Sample InputSample Output
    5
    1 2 3 4 1
    6

    题意:求Ai<Aj>Ak,i<j<k 的组合数。

    思路:这道题目其实是求逆序数,稍作变形,可以采用线段树或者树状数组来实现。两次扫描,先从前往后扫,即插即查,每插入一次,便计算该位置之前的总数并记录,再从后往前扫,原理相同。最后求对应位置乘积和。详情见代码:

    线段树实现:

     1 #include <fstream>
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 
     6 using namespace std;
     7 
     8 const int N=50002;
     9 int n,m,maxn,a[N],l[N];
    10 struct node
    11 {
    12     int left,right;
    13     int sum_;
    14 }tree[4*32770];
    15 
    16 void build(int id,int l,int r);//建一棵线段树
    17 int query_sum(int id,int l,int r);//查询区间和
    18 void update(int id,int pos);//更新位置pos的值增加1
    19 
    20 int main()
    21 {
    22     //freopen("D:\input.in","r",stdin);
    23     //freopen("D:\output.out","w",stdout);
    24     long long ans=0;
    25     scanf("%d",&n);
    26     for(int i=1;i<=n;i++)
    27         scanf("%d",&a[i]),maxn=max(a[i],maxn);
    28     build(1,1,maxn);
    29     for(int i=1;i<=n;i++)
    30     {
    31         update(1,a[i]);
    32         l[i]=query_sum(1,1,a[i]-1);
    33     }
    34     build(1,1,maxn);
    35     for(int i=n;i>=1;i--)
    36     {
    37         update(1,a[i]);
    38         ans+=l[i]*query_sum(1,1,a[i]-1);
    39     }
    40     printf("%lld
    ",ans);
    41     return 0;
    42 }
    43 void build(int id,int l,int r)
    44 {
    45     tree[id].left=l;
    46     tree[id].right=r;
    47     if(l==r)
    48     {
    49         tree[id].sum_=0;
    50     }
    51     else
    52     {
    53         int mid=(l+r)/2;
    54         build(2*id,l,mid);
    55         build(2*id+1,mid+1,r);
    56         tree[id].sum_=tree[2*id].sum_+tree[2*id+1].sum_;
    57     }
    58 }
    59 int query_sum(int id,int l,int r)
    60 {
    61     if(l>r) return 0;//注意参数的大小关系限制
    62     if(tree[id].left==l&&tree[id].right==r)
    63         return tree[id].sum_;
    64     else
    65     {
    66         int mid=(tree[id].left+tree[id].right)/2;
    67         if(r<=mid)  return query_sum(2*id,l,r);
    68         else if(l>mid)  return query_sum(2*id+1,l,r);
    69         else
    70             return query_sum(2*id,l,mid)+query_sum(2*id+1,mid+1,r);
    71     }
    72 }
    73 void update(int id,int pos)
    74 {
    75     if(tree[id].left==tree[id].right)
    76     {
    77         tree[id].sum_++;
    78     }
    79     else
    80     {
    81         int mid=(tree[id].left+tree[id].right)/2;
    82         if(pos<=mid)    update(2*id,pos);
    83         else update(2*id+1,pos);
    84         tree[id].sum_=tree[2*id].sum_+tree[2*id+1].sum_;
    85     }
    86 }
    View Code

    树状数组实现:

     1 #include <fstream>
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 
     6 using namespace std;
     7 
     8 int n,m,maxn;
     9 int a[50002],tree[32770],l[50002];
    10 
    11 int read(int pos);//求 sum[1,pos]的答案
    12 void update(int pos);//把a[pos]加上1
    13 
    14 int main()
    15 {
    16     //freopen("D:\input.in","r",stdin);
    17     //freopen("D:\output.out","w",stdout);
    18     long long ans=0;
    19     scanf("%d",&n);
    20     for(int i=1;i<=n;i++)
    21         scanf("%d",&a[i]),maxn=max(a[i],maxn);
    22     for(int i=1;i<=n;i++)
    23     {
    24         update(a[i]);
    25         l[i]=read(a[i]-1);
    26     }
    27     memset(tree,0,sizeof(tree));
    28     for(int i=n;i>=1;i--)
    29     {
    30         update(a[i]);
    31         ans+=l[i]*read(a[i]-1);
    32     }
    33     printf("%lld
    ",ans);
    34     return 0;
    35 }
    36 int read(int pos)
    37 {
    38     int ans=0;
    39     while(pos>0)
    40     {
    41         ans+=tree[pos];
    42         pos-=pos&(-pos);
    43     }
    44     return ans;
    45 }
    46 void update(int pos)
    47 {
    48     while(pos<=maxn)
    49     {
    50         tree[pos]++;
    51         pos+=pos&(-pos);
    52     }
    53 }
    View Code
  • 相关阅读:
    刷题篇--热题HOT 71-80
    刷题篇--热题HOT 61-70
    双飞翼布局介绍-始于淘宝UED
    css布局——百度前端技术学院
    CSS多列布局Multi-column、伸缩布局Flexbox、网格布局Grid详解
    CSS之BFC详解
    深入理解BFC和Margin Collapse
    CSS 布局_如何实现容器中每一行的子容器数量随着浏览器宽度的变化而变化?
    3列、2列自适应布局,中部内容优先显示3列布局等方法
    三列布局,中间自适应
  • 原文地址:https://www.cnblogs.com/jiu0821/p/4231391.html
Copyright © 2011-2022 走看看