贪心与最近的鞋子匹配(大小相同且方向相反),记$a_{x}$表示第x双鞋子的左位置,$b_{x}$表示右位置
若$a_{x}>b_{x}$,那么可以交换这两双鞋子并令答案+1,所以不妨设$a_{x}<b_{x}$
对于$x$和$y$,不妨设$a_{x}<a_{y}$,有结论:最终让第$x$双鞋子在第$y$双鞋子左边一定不劣
证明:对剩下的数位置关系(3种)分类讨论,比较两者的逆序对即可
根据分类讨论的讨论,用线段树来维护即可
[loj3175]排列鞋子_i++[loj3175]排列鞋子_分类讨论_02
 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 }
View Code