P1908 逆序对
传送门
这题似乎不应该出现在这里。。
日常做法(归并):
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<stack> #include<vector> #include<queue> #include<deque> #include<map> #include<set> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define maxn 2000003 typedef long long LL; LL n,ans=0; LL a[maxn],r[maxn]; inline LL read() { LL kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } void msort(LL s,LL t) { if(s==t) return ; LL mid=(s+t)/2; msort(s,mid); msort(mid+1,t); LL i=s,j=mid+1,k=s; while(i<=mid&&j<=t) { if(a[i]<=a[j]) r[k]=a[i],k++,i++; else { r[k]=a[j],k++,j++; ans+=mid-i+1; } } while(i<=mid) r[k]=a[i],k++,i++; while(j<=t) r[k]=a[j],k++,j++; for(LL i=s;i<=t;i++) a[i]=r[i]; } int main() { n=read(); for(LL i=1;i<=n;i++) a[i]=read(); msort(1,n); printf("%lld\n",ans); return 0; }
权值线段树做法:
需要先预处理,得到每个值在权值线段树中的位置;再按顺序将数字 a[ i ] 插入到树中相应的位置 ,接着询问树中比它大的元素个数,容易知道这些数都与当前的数 a[ i ] 形成逆序对,直接累加进 ans。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<stack> #include<vector> #include<queue> #include<deque> #include<map> #include<set> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define maxn 500002 typedef long long LL; LL n,ans=0; LL a[maxn]; struct hh { LL l_son,r_son,root; }sum[maxn<<2]; inline LL read() { LL kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } inline void build_sum(LL k,LL l,LL r) { sum[k].l_son=l;sum[k].r_son=r; if(l==r) return ; LL mid=sum[k].l_son+sum[k].r_son>>1; build_sum(k<<1,l,mid); build_sum(k<<1|1,mid+1,r); } inline void up_date(LL k,LL q) { if(q==sum[k].l_son&&q==sum[k].r_son) { sum[k].root++; return; } LL mid=sum[k].l_son+sum[k].r_son>>1; if(q<=mid) up_date(k<<1,q) ; else if(mid<q) up_date(k<<1|1,q); sum[k].root=sum[k<<1].root+sum[k<<1|1].root; } inline LL query(LL k,LL r,LL l) { if(r<=sum[k].l_son&&l>=sum[k].r_son ) return sum[k].root ; LL mid=(sum[k].l_son+sum[k].r_son)>>1; if (r>mid) return query(k<<1|1,r,l); else if(l<=mid) return query(k<<1,r,l); return query(k<<1,r,mid)+query(k<<1|1,mid+1,l); } int main() { n=read(); for(LL i=1;i<=n;i++) a[i]=read(); build_sum(1,1,n); for(LL i=1;i<=n;i++) { LL tmp=a[i]; up_date (1,tmp); ans+=i-query(1,1,tmp); } printf("%lld\n",ans); return 0; }