拖了很久今天终于下定决心来解决这道题了,这么经典的题目居然没有人写题解,本小白就来水一发(大佬勿喷),
希望能对大家有点帮助,主要讲下思想和两种方法的实现,感觉难点问题官方题解已经讲的很清楚了。
归并排序解法:
首先我们来看下为什么归并排序可以计算逆序对对数量:
比如一个数列为 5 4 1 2 3
首先在归并排序将数列分为两部分 5 4 1 和 2 3
左边 5 4 1再次分成两部分 5 4 和 1
然后5 4再被分为两部分,5和4
接着便开始逐步合并(重点来了):在合并的时候,由于5 排在 4前面,由于是从小到打排序,必然要先放置4,再放置5,这个时候我们便可以将逆序对+1了,该部分合并完成后变为 4 5,接着与 1合并,由于1比4,5都小,还排在4,5后面,这个时候要把1提前,变为1,4,5这样逆序对就+2,接下来的合并相同,这样排序完成便可以计算出逆序对的个数了。
注:这里只是思想,重点是代码!!!

#include<bits/stdc++.h>
using namespace std;
int a[100000],YHT[100086];//a数组为合并时候需要用于暂存的数组,YHT为初始数据存储的数组
int ans=0,l,r;
inline int read(){  //快读模板 
    int ans = 0, f = 1;
    char ch = getchar();
    if (ch == '-')
        f *= -1;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return ans * f;
}
void mergesort(int l,int r)//归并排序
{
    if(l==r) return;//先判断递归结束条件,当区间段只有一个元素的时候便可以结束
    int mid=(l+r)>>1;//   (l+r)/2与(l+r)>>1等同,但是后者更快,详情大家可以看看百度看看位运算;
    if(l<=mid) mergesort(l,mid);  //左递归
    if(mid+1<=r) mergesort(mid+1,r);//右递归
    int ln=l,rn=mid+1,k=l;  //合并操作   比如l-mid 为 1 3 4  mid+1-r为 2 6 7 一开始ln指向左部第一个元素即1,rn指向右部第一个元素即2,k用于存储的时候记录位置,一开始指向该区段最左边位置
    while(ln<=mid&&rn<=r)
    {
        if(YHT[ln]<YHT[rn]) a[k++]=YHT[ln++];
        else
        {
            a[k++]=YHT[rn++];//右部的放到前面来
            ans+=mid-ln+1;//mid-ln+1为还没有放置的左部元素,即为和这部操作放置元素组成逆序对的元素
        }
    }
    while(ln<=mid) a[k++]=YHT[ln++];
    while(rn<=r) a[k++]=YHT[rn++];
    for(int i=l;i<=r;i++)//将暂存数组中的数据放入主数组中
    {
        YHT[i]=a[i];
    } 
}

int main()
{


    int n,m;
    n=read(); 
    for(int i=0;i<n;i++)
    {
        YHT[i]=read();
    } 
    mergesort(0,n-1);
    m=read(); 
    ans%=2;//判断逆序对个数的奇偶性
    while(m--)
    {
        l=read();
        r=read();
        int p=(r-l+1)*(r-l)/2;
        if(p&1) ans^=1;//p&1与p%2==1等同,因为只有p是奇数才可以能对逆序对的奇偶性产生影响,因为ans非0,即1,相互转化用异或即可
        if(ans) printf("dislike\n");
        else printf("like\n"); 
    }

}

图片说明

2.树状数组
图片说明
树状数组能快速求出前缀和,这里可以讲前缀和看作是逆序对的数列,还是举个例子吧
元素:5 4 1 3 2
下标:1 2 3 4 5
我们可以讲数组从大到小排序,下标不变:
排序后为:
元素 5 4 3 2 1
下表 1 2 4 5 3
这样就能保证先加入比后加入的大
初始状态树状数组为0 0 0 0 0
先加入5,5对应的下标为1,树状数组变为1 0 0 0 0
接着加入4,4对应的下标是2,树状数组变为 1 1 0 0 0
这时我们发现2前面已经有加入的,这样便构成一个逆序对,需要加1
接着加入3,3对应的下标为4,树状数组变为 1 1 0 1 0
4坐标前的前缀和为2(1+1),所以这样又有两个逆序对
每次都这样,最后便可以求出逆序对个数,因为树状数组可以用于快速求前缀和,便可以使用他来加快速度。
注:这只是思想,希望大家能去学习树状数组的写法,确实是个好东西。由于本人也刚起步,理解也只有这种水平了。

#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int num;//位置下标
    int val;//值
};
Node a[100086];
int YHT[100086];
int n,m,ans=0,l,r;

inline int read() {
    int ans = 0, f = 1;
    char ch = getchar();
    if (ch == '-')
        f *= -1;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return ans * f;
}
int lowbit(int x)//树状数组模板
{
    return x&(-x);
}
void update(int x)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        YHT[i]+=1;
    }
}
int query(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
    {
        sum+=YHT[i];
    }
    return sum;
}

bool cmp(Node a,Node b)//定义排序方法
{
    return a.val>b.val;
}

int main()
{

    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].val=read();
        a[i].num=i;
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        ans+=query(a[i].num);//求前缀和
        update(a[i].num);//更新
    }
    ans%=2;
    m=read();
    while(m--)
    {
        l=read();
        r=read();
        int p=(r-l+1)*(r-l)/2;
        if(p&1) ans^=1;
        if(ans) printf("dislike\n");
        else printf("like\n");

    }
} 

小白写题解不易,大家如果觉得有帮助的话,点个赞哦,祝大家天天AC。