标签:图片 close 表示 cst span har show getch lld
这道题我采用树状数组求解逆序对一类的思想解决
我们读入数据之后,分析问题,本题求解两个问题:‘^’的数量和‘v’的数量,我们先考虑^
假设我们令i为^的那个顶点,那么以i为顶点的^的个数就是i左侧高度小于i的高度的个数与右侧高度小于i的数量的乘积,我们只需要枚举i的位置,累加答案即可。
我们如何高效的维护i两侧小于i高度的数量?我们建立一个树状数组(当然线段树也可以)存储每一个高度出现的次数。
我们正序枚举i,对于每一个i,我们在树状数组中查找0~a[i]-1的数量,这个数量就是在i左侧高度小于i的高度的个数,查找完成后,我们将a[i]这个高度在树状数组中+1,表示出现过一次。
我们再进行一次逆序枚举,即可求出在i右侧高度小于i的数量。之后我们就可以求解^的数量
同理,我们也可以求解V的数量。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int N=200010; 8 int n,a[N],sum[N]; 9 ll ans,l[N],r[N]; 10 inline int read() { 11 int ret=0; 12 int op=1; 13 char c=getchar(); 14 while(c<‘0‘||c>‘9‘) {if(c==‘-‘) op=-1; c=getchar();} 15 while(c<=‘9‘&&c>=‘0‘) ret=ret*10+c-‘0‘,c=getchar(); 16 return ret*op; 17 } 18 inline int lowbit(int x) { 19 return -x&x; 20 } 21 inline int query(int x) { 22 int ret=0; 23 while(x) { 24 ret+=sum[x]; 25 x-=lowbit(x); 26 } 27 return ret; 28 } 29 inline void add(int x) { 30 while(x<=n) { 31 sum[x]++; 32 x+=lowbit(x); 33 } 34 } 35 int main() { 36 n=read(); 37 for(int i=1;i<=n;i++) a[i]=read(); 38 for(int i=1;i<=n;i++) { 39 l[i]=query(n)-query(a[i]); 40 add(a[i]); 41 } 42 memset(sum,0,sizeof(sum)); 43 for(int i=n;i>=1;i--) { 44 r[i]=query(n)-query(a[i]); 45 add(a[i]); 46 } 47 for(int i=1;i<=n;i++) 48 ans+=(long long)l[i]*r[i]; 49 printf("%lld ",ans); 50 ans=0; 51 memset(sum,0,sizeof(sum)); 52 memset(l,0,sizeof(l)); 53 memset(r,0,sizeof(r)); 54 for(int i=1;i<=n;i++) { 55 l[i]=query(a[i]-1); 56 add(a[i]); 57 } 58 memset(sum,0,sizeof(sum)); 59 for(int i=n;i>=1;i--) { 60 r[i]=query(a[i]-1); 61 add(a[i]); 62 } 63 for(int i=1;i<=n;i++) 64 ans+=(long long)l[i]*r[i]; 65 printf("%lld",ans); 66 return 0; 67 }
标签:图片 close 表示 cst span har show getch lld
原文地址:https://www.cnblogs.com/shl-blog/p/10920718.html