楼兰图腾(树状数组)
题目:
题目描述
在完成了分配任务之后,西部314来到了楼兰古城的西部。
相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(‘V’),一个部落崇拜铁锹(‘∧’),他们分别用V和∧的形状来代表各自部落的图腾。
西部314在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了N个点,经测量发现这N个点的水平位置和竖直位置是两两不同的。
西部314认为这幅壁画所包含的信息与这N个点的相对位置有关,因此不妨设坐标分别为(1,y1),(2,y2),…,(n,yn),其中y1~yn是1到n的一个排列。
西部314打算研究这幅壁画中包含着多少个图腾。
如果三个点(i,yi),(j,yj),(k,yk)满足1≤i[HTML_REMOVED]yj,yj<yk,则称这三个点构成V图腾;
如果三个点(i,yi),(j,yj),(k,yk)满足1≤i[HTML_REMOVED]yk,则称这三个点构成∧图腾;
西部314想知道,这n个点中两个部落图腾的数目。
因此,你需要编写一个程序来求出V的个数和∧的个数。
解题报告:
咱们只需要求解的就是每个点左右两侧分别高于它和小于它的数目,就可以求出该点可以够成的V和A的数目,最后累加一下就可以,但是由于树状数组只可以求解该前边的的数目,所以转换了一下思想,就是使用getsum(n)-getsum(a[i]-1),就可以实现求解后边的数目。
ac代码:
1 //from:Onion 2 //acwing 241 楼兰图腾 树状数组 3 4 #include<iostream> 5 #include<algorithm> 6 #include<cstring> 7 #include<cstdio> 8 #include<cmath> 9 using namespace std; 10 typedef long long ll; 11 12 int n; 13 const int maxn =2e5+1000; 14 ll a[maxn],t[maxn],left1[maxn],right1[maxn],left2[maxn],right2[maxn]; 15 16 ll lowbit(int x) 17 { 18 return x&-x; 19 } 20 void add(int x,int val) 21 { 22 while(x<=n) 23 { 24 t[x]+=val; 25 x+=lowbit(x); 26 } 27 } 28 ll getsum(int x) 29 { 30 ll ans=0; 31 while(x>0) 32 { 33 ans+=t[x]; 34 x-=lowbit(x); 35 } 36 return ans; 37 } 38 39 int main() 40 { 41 scanf("%d",&n); 42 ll mx=0; 43 for(int i=1;i<=n;i++) 44 { 45 scanf("%lld",&a[i]); 46 mx=max(mx,a[i]); 47 } 48 memset(t,0,sizeof(t)); 49 for(int i=n;i>0;i--) 50 { 51 right1[i]=getsum(n)-getsum(a[i]); 52 right2[i]=getsum(a[i]-1); 53 add(a[i],1); 54 } 55 memset(t,0,sizeof(t)); 56 ll ans1=0,ans2=0; 57 for(int i=1;i<=n;i++) 58 { 59 left1[i]=getsum(n)-getsum(a[i]); 60 left2[i]=getsum(a[i]-1); 61 add(a[i],1); 62 ans1+=left1[i]*right1[i]; 63 ans2+=left2[i]*right2[i]; 64 } 65 printf("%lld %lld\n",ans1,ans2); 66 }