codeforeces 540E(树状数组
题意:交换自然数中的若干对数,求交换后总共有多少逆序数对。
思路:因为题目数字范围比较大,不能直接用树状数组算,首先要离散化。然后一种算法是官方题解中根据逆序对数是否属于交换过的数分类讨论统计。我的算法是把没有交换的连续的数看成一个数,使用树状数组统计的时候直接加上这个区间的数字个数,这样就不需要比较易错的讨论了。
#include<iostream> #include<map> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<queue> #include<stack> #include<functional> #include<set> #define pb push_back #define fs first #define se second using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int maxv=1e5*4; struct BIT{ ll a[maxv]; void add(int p,int x){ while(p<maxv){ a[p]+=x; p+=p&-p; } } ll sum(int p){ ll ans=0; while(p>0){ ans+=a[p]; p-=p&-p; } return ans; } ll after(int a){ return sum(maxv-1)-sum(a); } }B; int a[maxv]; int b[maxv]; int c[maxv]; int mid[maxv]; int sq[maxv]; int n; map<int,int> mii; int main(){ freopen("/home/files/CppFiles/in","r",stdin); cin>>n; for(int i=0;i<n;i++){ scanf("%d%d",a+i,b+i); c[i*2]=a[i]; c[i*2+1]=b[i]; } sort(c,c+2*n); int h=unique(c,c+2*n)-c; for(int i=1;i<h;i++){ mid[i]=c[i]-c[i-1]-1; } for(int i=0;i<h;i++){ mii[c[i]]=i+1; } for(int i=0;i<maxv;i++){ sq[i]=i; } for(int i=0;i<n;i++){ swap(sq[mii[a[i]]],sq[mii[b[i]]]); } ll ans=0; for(int i=1;i<=h;i++){ ll now=sq[i]; ans+=B.after(now*2-1); B.add(now*2-1,1); ans+=mid[i]*B.after(i*2); B.add(2*i,mid[i]); } cout<<ans<<endl; return 0; }