hdu 5792 线段树+离散化+思维
Posted Go
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5792 线段树+离散化+思维相关的知识,希望对你有一定的参考价值。
题目大意:
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; }
以上是关于hdu 5792 线段树+离散化+思维的主要内容,如果未能解决你的问题,请参考以下文章
HDU1542-Atlantis离散化&线段树&扫描线个人认为很全面的详解