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 Input Sample 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\n",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\n",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

你可能感兴趣的:(树状数组)