题目大意:
Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ada≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad.
A1,A2?AnA1,A2?An. 1≤n≤500001≤n≤50000 0≤Ai≤1e9
基本思路:
最朴素的思想就是算出所有顺序对所有逆序对相乘然后再减去所有有重复元素的结果,最终得到答案;基本思路和树状数组还是一致的;
反思与总结:
之前学线段树的时候貌似学的太浅了,区间更新的lazy标记没学,就是那个PushDown函数,这次专门去理解了一下,我的理解是,如果每次都向下找到每个叶节点再操作非常的费时间,解决方法就用个lazy标记(就是我程序里的add数组),除非用到每一段,否则不再向下递归,指示标记到当前结点,这样能大大节省时间(详细的讲解看我的线段树,其实多半都是转的大佬们的);
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> using namespace std; typedef long long ll; const int maxn = 50000+10; int arr[maxn],tmp[maxn]; int lx[maxn],rx[maxn],ld[maxn],rd[maxn]; int sum[maxn],num[maxn]; int ans[maxn<<2],add[maxn<<2]; int n; map<int,int>mm; void PushUp(int root) { ans[root]=ans[root<<1]+ans[root<<1|1]; } void build(int l,int r,int root) { add[root]=0; if(l==r) { ans[root]=0; return; } int m=(l+r)>>1; build(l,m,root<<1); build(m+1,r,root<<1|1); PushUp(root); } void PushDown(int l,int r,int root) { if(add[root]) { add[root<<1]+=add[root]; add[root<<1|1]+=add[root]; ans[root<<1]+=add[root<<1]; ans[root<<1|1]+=add[root<<1|1]; add[root]=0; } } void update(int ql,int qr,int l,int r,int root) { if(qr<l||ql>r) return; if(ql<=l&&qr>=r) { ans[root]+=1; add[root]+=1; return; } PushDown(l,r,root); int m=(l+r)>>1; if(ql<=m) update(ql,qr,l,m,root<<1); if(qr>m) update(ql,qr,m+1,r,root<<1|1); PushUp(root); } int query(int ql,int qr,int l,int r,int root) { if(qr<l||ql>r) return 0; if(ql<=l&&qr>=r) return ans[root]; PushDown(l,r,root); int m=(l+r)>>1; return query(ql,qr,l,m,root<<1)+query(ql,qr,m+1,r,root<<1|1); } int main() { while(scanf("%d",&n)==1) { mm.clear(); for(int i=1;i<=n;i++) { scanf("%d",&arr[i]); tmp[i]=arr[i]; } sort(tmp+1,tmp+n+1); sum[0]=add[0]=0; int cnt=0; for(int i=1;i<=n;i++) { if(!mm[tmp[i]]) { mm[tmp[i]]=++cnt; num[cnt]=1; sum[cnt]=sum[cnt-1]+num[cnt-1]; } else num[cnt]++; } build(1,cnt,1); for(int i=1;i<=n;i++) { int order=mm[arr[i]]; update(order,order,1,cnt,1); lx[i]=query(1,order-1,1,cnt,1); ld[i]=query(order+1,cnt,1,cnt,1); rx[i]=sum[order]-lx[i]; rd[i]=n-lx[i]-rx[i]-ld[i]-num[order]; } ll res=0; ll x=0,y=0; for(int i=1;i<=n;i++) { x+=lx[i]; y+=ld[i]; } res=x*y; for(int i=1;i<=n;i++) { res-=lx[i]*ld[i]; res-=rd[i]*rx[i]; res-=lx[i]*rx[i]; res-=rd[i]*ld[i]; } printf("%I64d\n",res); } return 0; }
时间: 2024-10-09 23:49:29