数列(queue)
时间限制: 3000 ms 内存限制: 65536 KB
【题目描述】
一个简单的数列问题,给定一个长度为nn的数列,求这样的三个元素a1,a2,a3a1,a2,a3的个数,满足ai<aj>akai<aj>ak,且i<j<ki<j<k。
【输入】
第一行一个整数n(1≤n≤50000)n(1≤n≤50000)。
接下来nn行,每行一个元素ai(0≤ai≤32767)ai(0≤ai≤32767)。
【输出】
输出一行一个整数,表示满足ai<aj>akai<aj>ak的个数。
【输入样例】
5 1 2 3 4 1
【输出样例】
6
【提示】
【数据范围】
对于30%的输入数据n≤200n≤200;
对于80%的输入数据n≤10000n≤10000。
【思路分析】
这道题很显然是一道求逆序对的题,那么求逆序对的方法很多,最好写也是很好理解的就是归并排序,但是发现这道题用归并没思路,因为并不知道如何用归并求出每一项的逆序对个数(可能是我太菜了)所以我就写了一个线段树的逆序对,我们这里还是解释一下如何用线段树求逆序对,我们每次插入一个数之后,我们就查询这个数之后的线段树中有多少个数已经被插入了,因为在这个数之后的数一定大于这个数,并且在它之前插入,那么一定就是逆序对了,所以就实现了线段树查逆序对。
那么了解之后,我们就可以用线段树查询了,其实发现这有3对,其实就是顺着求一遍逆序对,再反着求一遍逆序对,然后将当前数两次查到的个数相乘就可以求出以每个数为中心的3组数对了。
【代码实现】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 struct sd{ 7 int l,r,num,son[2]; 8 }tree[150767]; 9 int sum=0; 10 int root=1; 11 const int lr=32777; 12 long long ans; 13 int len1[500005],len2[500005]; 14 void build(int &v,int l1,int r1) 15 { 16 sum++;v=sum; 17 tree[v].l=l1,tree[v].r=r1,tree[v].num=0; 18 if(l1==r1) 19 { 20 tree[v].num=0; 21 return; 22 } 23 int mid=(l1+r1)/2; 24 build(tree[v].son[0],l1,mid); 25 build(tree[v].son[1],mid+1,r1); 26 } 27 int dfs(int v,int l1,int r1) 28 { 29 if(r1<l1) return 0; 30 if(tree[v].l==l1&&tree[v].r==r1) 31 return tree[v].num; 32 int mid=(tree[v].l+tree[v].r)/2; 33 if(r1<=mid) 34 return dfs(tree[v].son[0],l1,r1); 35 else 36 if(l1>mid) 37 return dfs(tree[v].son[1],l1,r1); 38 else 39 return dfs(tree[v].son[0],l1,mid)+dfs(tree[v].son[1],mid+1,r1); 40 } 41 void add(int key,int v,int l,int r,int orz,int id) 42 { 43 if(l==r&&l==key) 44 { 45 tree[v].num++; 46 if(orz==1) 47 len1[id]=dfs(1,0,l-1); 48 else 49 len2[id]=dfs(1,0,l-1); 50 return; 51 } 52 int mid=(l+r)/2; 53 if(key<=mid) 54 add(key,tree[v].son[0],l,mid,orz,id); 55 else 56 add(key,tree[v].son[1],mid+1,r,orz,id); 57 tree[v].num=tree[tree[v].son[0]].num+tree[tree[v].son[1]].num; 58 } 59 int a[500005]; 60 int main() 61 { 62 int n; 63 scanf("%d",&n); 64 build(root,0,lr); 65 for(int i=1;i<=n;i++) 66 { 67 scanf("%d",&a[i]); 68 } 69 for(int i=1;i<=n;i++) 70 add(a[i],1,0,lr,1,i); 71 root=1,sum=0; 72 build(root,0,lr); 73 for(int i=n;i>=1;i--) 74 { 75 add(a[i],1,0,lr,2,i); 76 } 77 ans=0; 78 for(int i=1;i<=n;i++) 79 { 80 ans=(ans+(len1[i]*len2[i])%mod)%mod; 81 } 82 printf("%lld",ans); 83 return 0; 84 }