题意:有一个1,2,3,4...无限序列,进行m次操作,每次交换i,j位置上的数,问操作完以后有多少对逆序数。
思路:来自:点击打开链接
思维点在于将没有操作过的连续序列也离散成一个点,权值为序列中数的个数,这样就可以无脑进行交换操作,然后用树状数组统计一下逆序对数就好了(注意每个点有权值)。
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> P;
const int MAXN = 400010;
P p[MAXN];
int val[MAXN], w[MAXN], num[MAXN];
ll bit[MAXN];
map<int, int> pos;
void add(int i, int x, int n)
{
while(i <= n)
{
bit[i] += x;
i += i & -i;
}
}
ll sum(int i)
{
ll res = 0;
while(i)
{
res += bit[i];
i -= i & -i;
}
return res;
}
int main()
{
int n, cnt = 0;
cin >> n;
for(int i = 0; i < n; i++)
{
scanf("%d %d", &p[i].first, &p[i].second);
val[cnt++] = p[i].first;
val[cnt++] = p[i].second;
}
sort(val, val + cnt);
cnt = unique(val, val + cnt) - val;
int tid = 1;
w[tid] = 1; pos[val[0]] = tid;
for(int i = 1; i < cnt; i++)
{
if(val[i] > val[i - 1] + 1)
w[++tid] = val[i] - val[i - 1] - 1;
w[++tid] = 1;
pos[val[i]] = tid;
}
for(int i = 1; i <= tid; i++) num[i] = i;
for(int i = 0; i < n; i++) swap(num[pos[p[i].first]], num[pos[p[i].second]]);
ll ans = 0;
for(int i = tid; i >= 1; i--)
{
ans += sum(num[i]) * w[i];
add(num[i], w[i], tid);
}
cout << ans << endl;
return 0;
}