本题求逆序对的思路还是按照归并排序的过程去求解,但不同之处在于本题需要不断的变换区间里面数的排列。首先考虑在每一次变换之后都去求解逆序对的数量肯定是会超时的。
然后可以联想到如果在区间发生变化之后快速求出逆序对的个数,即可发现在一个区间里面翻转之后逆序对的个数=区间里面的对数-翻转之前逆序对的个数。
可以列出公式:ans-(r-l+1)*(r-l)/2-2x(ans是逆序对的总个数,x是反转之前区间里面逆序对的个数)。可知2x必然是偶数,那么ans奇偶性的变化就取决于(r-l+1)*(r-l)/2,
解到这里就可以发现每一个奇偶性的变化仅仅取决于(r-l+1)*(r-l)/2的奇偶性。这样就可以不必要从新去求逆序对的个数。
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int maxn = 1e5+10; int a[maxn]; int temp[maxn]; ll cnt = 0; int read() { int num = 0, k = 1; char c = getchar(); while (!(c=='-'||(c>='0'&&c<='9'))) { c = getchar(); } while (c=='-') { k = -k; c = getchar(); } while (c>='0'&&c<='9') { num = num*10 + (c-'0'); c = getchar(); } return num*k; } void Merge(int l1, int r1, int l2, int r2) { memset(temp, 0, sizeof(temp)); int n = 0, begin = l1; while (l1<=r1&&l2<=r2) { if (a[l1]<=a[l2]) temp[n++] = a[l1++]; else { temp[n++] = a[l2++]; cnt += r1-l1+1; } } while (l1<=r1) temp[n++] = a[l1++]; while (l2<=r2) temp[n++] = a[l2++]; for (int i=0;i<n;i++) { a[begin+i] = temp[i]; } } void find_inv_num(int l, int r) { if (l==r) return ; int mid = (l+r)/2; find_inv_num(l, mid); find_inv_num(mid+1, r); Merge(l, mid, mid+1, r); } int main() { int n; scanf("%d", &n); for (int i=1;i<=n;i++) { a[i] = read(); } find_inv_num(1, n); int p; if (cnt%2==0) p = 1; else p = 0; int m; int l, r; scanf("%d", &m); while (m--) { l = read();r=read(); int jio = (r-l+1)*(r-l)/2; if (jio&1==1) { p = p^1; } if (p) { printf("like\n"); } else { printf("dislike\n"); } } return 0; }