谈谈逆序对
谈谈逆序对
归并排序
归并排序将一个大区间分成两个小区间,其中保证了右区间的\(id\)是比左区间大的,且两区间分别有序。
所以我们只需要逐个对照,判断有多少对\(a[j] < a[i]\)(\(i\)为左指针,\(j\)为右指针),遇到\(a[j] < a[i]\)的情况就说明\(a[j]\)与所有未被合并的左区间点都能产生逆序对,提供\(mid - i + 1\)的贡献。因为此时的\(a[i]\)是左区间所有未被合并的点的最小值。即\(id[j] > id[i]\) && \(a[j] < a[i]\)。
#ifndef DEBUG
#define NDEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
namespace IO {
char ibuf[1 << 21], *p1 = ibuf, *p2 = ibuf, obuf[1 << 21], *p = obuf;
#ifdef DEBUG
inline char gc() {
return getchar();
}
inline void pc(char ch) {
putchar(ch);
}
struct outflush {};
#else
inline char gc() {
return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline void pc(char ch) {
p == obuf + sizeof(obuf) && (fwrite(obuf, 1, 1 << 21, stdout), p == obuf), *p++ = ch;
}
inline void ioflush() {
fwrite(obuf, 1, p - obuf, stdout), fflush(stdout), p = obuf;
}
struct outflush {
~outflush() {
ioflush();
fclose(stdin);
fclose(stdout);
}
} flushout;
#endif
inline void read() {}
template<class T, class... Args> inline void read(T &x, Args&... args) {
x = 0; char ch; bool sgn = true;
while (!isdigit(ch = gc())) sgn = ch != '-';
if (sgn) do x = x * 10 + (ch & 15); while (isdigit(ch = gc()));
else do x = x * 10 - (ch & 15); while (isdigit(ch = gc()));
read(args...);
}
template<class T> inline void prin(T x, char ch = EOF) {
if (x < 0) pc('-'), x = ~x + 1;
static int buf[sizeof(T) * 3], top = 0;
while (x) buf[++top] = x % 10, x /= 10;
if (!top) buf[++top] = 0;
while (top) pc(buf[top--] ^ 48);
if (~ch) pc(ch);
}
}
using IO::gc, IO::pc, IO::read, IO::prin, IO::outflush;
using ll = long long;
const int MN = 5e5 + 5;
int n;
ll ans;
int a[MN], tmp[MN];
void merge_sort(int l, int r) {
if (l == r) return ;
int mid = l + (r - l >> 1), i = l, j = mid + 1, k = l;
merge_sort(l, mid), merge_sort(mid + 1, r);
while (i <= mid && j <= r) {
if (a[i] <= a[j]) tmp[k++] = a[i++];
else {
tmp[k++] = a[j++];
ans += mid - i + 1;
}
}
while (i <= mid) tmp[k++] = a[i++];
while (j <= r) tmp[k++] = a[j++];
for (int p = l; p <= r; ++p) a[p] = tmp[p];
}
signed main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
read(n);
for (int i = 1; i <= n; ++i) read(a[i]);
merge_sort(1, n);
prin(ans, '\n');
return 0;
}
树状数组
一种不离散化,最简单思路:按照\(val\)自小到大排序,然后挨个把它们的\(id\)加进树状数组,每次的贡献为\(i - query(id[i])\)(即总共\(i\)个数,抛去比\(id\)比\(i\)小的数的个数,我们排序已经保证其他数的\(val\)比\(i\)小,只需要找\(id\)比\(i\)大的数即可。
#ifndef DEBUG
#define NDEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
namespace IO {
char ibuf[1 << 21], *p1 = ibuf, *p2 = ibuf, obuf[1 << 21], *p = obuf;
#ifdef DEBUG
inline char gc() {
return getchar();
}
inline void pc(char ch) {
putchar(ch);
}
struct outflush {};
#else
inline char gc() {
return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline void pc(char ch) {
p == obuf + sizeof(obuf) && (fwrite(obuf, 1, 1 << 21, stdout), p == obuf), *p++ = ch;
}
inline void ioflush() {
fwrite(obuf, 1, p - obuf, stdout), fflush(stdout), p = obuf;
}
struct outflush {
~outflush() {
ioflush();
fclose(stdin);
fclose(stdout);
}
} flushout;
#endif
inline void read() {}
template<class T, class... Args> inline void read(T &x, Args&... args) {
x = 0; char ch; bool sgn = true;
while (!isdigit(ch = gc())) sgn = ch != '-';
if (sgn) do x = x * 10 + (ch & 15); while (isdigit(ch = gc()));
else do x = x * 10 - (ch & 15); while (isdigit(ch = gc()));
read(args...);
}
template<class T> inline void prin(T x, char ch = EOF) {
if (x < 0) pc('-'), x = ~x + 1;
static int buf[sizeof(T) * 3], top = 0;
while (x) buf[++top] = x % 10, x /= 10;
if (!top) buf[++top] = 0;
while (top) pc(buf[top--] ^ 48);
if (~ch) pc(ch);
}
}
using IO::gc, IO::pc, IO::read, IO::prin, IO::outflush;
using ll = long long;
const int MN = 5e5 + 5;
int n;
ll ans;
int sum[MN];
pair<int, int> a[MN];
void add(int x, int y) {
for (; x <= n; x += x & -x) sum[x] += y;
}
ll query(int x) {
ll ret = 0;
for (; x; x -= x & -x) ret += sum[x];
return ret;
}
signed main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
read(n);
for (int i = 1; i <= n; ++i) {
read(a[i].second);
a[i].first = i;
}
sort(a + 1, a + n + 1, [](pair<int, int> x, pair<int, int> y) {
return x.second != y.second ? x.second < y.second : x.first < y.first;
});
for (int i = 1; i <= n; ++i) {
add(a[i].first, 1);
ans += i - query(a[i].first);
}
prin(ans, '\n');
return 0;
}
第二种,设一数组\(rnk\),将\(rnk[id[i]]\)记为\(i\),即下标为它的\(id\),\(val\)为它的实际数值的排名。
\(for\)循环从1到n遍历\(rnk[i]\),保证\(id\)一定从小到大,每次把\(rnk[i]\)加入树状数组,相当于是把它的排名加入树状数组,每次查询有多少比它排名大的数,即\(ans += i - query(rnk[i])\)。
#ifndef DEBUG
#define NDEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
namespace IO {
char ibuf[1 << 21], *p1 = ibuf, *p2 = ibuf, obuf[1 << 21], *p = obuf;
#ifdef DEBUG
inline char gc() {
return getchar();
}
inline void pc(char ch) {
putchar(ch);
}
struct outflush {};
#else
inline char gc() {
return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline void pc(char ch) {
p == obuf + sizeof(obuf) && (fwrite(obuf, 1, 1 << 21, stdout), p == obuf), *p++ = ch;
}
inline void ioflush() {
fwrite(obuf, 1, p - obuf, stdout), fflush(stdout), p = obuf;
}
struct outflush {
~outflush() {
ioflush();
fclose(stdin);
fclose(stdout);
}
} flushout;
#endif
inline void read() {}
template<class T, class... Args> inline void read(T &x, Args&... args) {
x = 0; char ch; bool sgn = true;
while (!isdigit(ch = gc())) sgn = ch != '-';
if (sgn) do x = x * 10 + (ch & 15); while (isdigit(ch = gc()));
else do x = x * 10 - (ch & 15); while (isdigit(ch = gc()));
read(args...);
}
template<class T> inline void prin(T x, char ch = EOF) {
if (x < 0) pc('-'), x = ~x + 1;
static int buf[sizeof(T) * 3], top = 0;
while (x) buf[++top] = x % 10, x /= 10;
if (!top) buf[++top] = 0;
while (top) pc(buf[top--] ^ 48);
if (~ch) pc(ch);
}
}
using IO::gc; using IO::pc; using IO::read; using IO::prin; using IO::outflush;
using ll = long long;
const int MN = 5e5 + 5;
int n;
ll ans;
int sum[MN];
ll rnk[MN];
pair<int, int> a[MN];
void add(int x, int y) {
for (; x <= n; x += x & -x) sum[x] += y;
}
ll query(int x) {
ll ret = 0;
for (; x; x -= x & -x) ret += sum[x];
return ret;
}
signed main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
read(n);
for (int i = 1; i <= n; ++i) {
read(a[i].first);
a[i].second = i;
}
sort(a + 1, a + n + 1, [](const pair<int, int> &x, const pair<int, int> &y) {
return x.first != y.first ? x.first < y.first : x.second < y.second;
});
for (int i = 1; i <= n; ++i) rnk[a[i].second] = i;
for (int i = 1; i <= n; ++i) {
add(rnk[i], 1);
ans += i - query(rnk[i]);
}
prin(ans, '\n');
return 0;
}
本文来自博客园,作者:zjsqwq,转载请注明原文链接:https://www.cnblogs.com/zjsqwq/p/16452829.html

浙公网安备 33010602011771号