[loj3175]排列鞋子
贪心与最近的鞋子匹配(大小相同且方向相反),记$a_{x}$表示第x双鞋子的左位置,$b_{x}$表示右位置
若$a_{x}>b_{x}$,那么可以交换这两双鞋子并令答案+1,所以不妨设$a_{x}<b_{x}$
对于$x$和$y$,不妨设$a_{x}<a_{y}$,有结论:最终让第$x$双鞋子在第$y$双鞋子左边一定不劣
证明:对剩下的数位置关系(3种)分类讨论,比较两者的逆序对即可
根据分类讨论的讨论,用线段树来维护即可
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 struct ji{ 8 int a,b; 9 }a[N]; 10 vector<int>va[N],vb[N]; 11 int n,x,f[N<<3]; 12 long long ans; 13 bool cmp(ji x,ji y){ 14 return x.a<y.a; 15 } 16 void update(int k,int l,int r,int x){ 17 f[k]++; 18 if (l==r)return; 19 if (x<=mid)update(L,l,mid,x); 20 else update(R,mid+1,r,x); 21 } 22 int query(int k,int l,int r,int x,int y){ 23 if((l>y)||(x>r))return 0; 24 if ((x<=l)&&(r<=y))return f[k]; 25 return query(L,l,mid,x,y)+query(R,mid+1,r,x,y); 26 } 27 int main(){ 28 scanf("%d",&n); 29 for(int i=1;i<=2*n;i++){ 30 scanf("%d",&x); 31 if (x>0)vb[x].push_back(i); 32 else va[-x].push_back(i); 33 } 34 x=0; 35 for(int i=1;i<=n;i++) 36 for(int j=0;j<va[i].size();j++){ 37 a[++x].a=va[i][j]; 38 a[x].b=vb[i][j]; 39 if (a[x].a>a[x].b){ 40 ans++; 41 swap(a[x].a,a[x].b); 42 } 43 } 44 sort(a+1,a+n+1,cmp); 45 for(int i=n;i;i--){ 46 ans+=query(1,1,2*n,1,a[i].b-1); 47 update(1,1,2*n,a[i].a); 48 update(1,1,2*n,a[i].b); 49 } 50 printf("%lld",ans); 51 }