您的位置:首页 > 其它

CodeForces 785E Anton and Permutation 分块

2017-03-18 16:09 369 查看

题意:

有一个\(1 \sim n\)的排列\(A\),有\(q\)个询问:

交换任意两个元素的位置,求交换之后排列的逆序数

分析:

像这种不太容易用线段树,树状数组维护的可以考虑分块

每\(\sqrt{n}\)个元素划分为一块,然后两端的块可以直接扫出逆序数的变化,中间的块可以用二分计算逆序数

在更新块的时候,可以二分查找要插入或删除的位置

每次询问的复杂度为\(O(\sqrt{n}log\sqrt{n})=O(\sqrt{n}logn)\)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn = 200000 + 10;
const int maxsqrt = 500;

#define ALL(x) x.begin(), x.end()

int n, q, a[maxn];
int st[maxsqrt], ed[maxsqrt];
vector<int> b[maxsqrt];

int main()
{
scanf("%d%d", &n, &q);
int col = (int)sqrt(n);
for(int i = 0; i < n / col; i++) { st[i] = col * i; ed[i] = col * (i + 1); }
if(n % col > 0) { st[n / col] = n - (n % col); ed[n / col] = n; }

for(int i = 0; i < n; i++) {
a[i] = i;
b[i / col].push_back(i);
}

long long ans = 0;
while(q--) {
int l, r; scanf("%d%d", &l, &r);
l--; r--;
if(l == r) { printf("%lld\n", ans); continue; }
if(l > r) swap(l, r);
int idl = l / col, idr = r / col;

//update
for(int i = idl + 1; i < idr; i++) {
int size = b[i].size();
int p = lower_bound(ALL(b[i]), a[l]) - b[i].begin();
ans -= p;
ans += size - p;
p = lower_bound(ALL(b[i]), a[r]) - b[i].begin();
ans += p;
ans -= size - p;
}

for(int i = l + 1; i < ed[idl] && i < r; i++) {
if(a[i] > a[l]) ans++; else ans--;
if(a[i] > a[r]) ans--; else ans++;
}
for(int i = st[idr]; i < r && i > l; i++) {
if(a[i] > a[l]) ans++; else ans--;
if(a[i] > a[r]) ans--; else ans++;
}

//swap
if(idl < idr) {
b[idl].erase(lower_bound(ALL(b[idl]), a[l]));
b[idl].insert(lower_bound(ALL(b[idl]), a[r]), a[r]);
b[idr].erase(lower_bound(ALL(b[idr]), a[r]));
b[idr].insert(lower_bound(ALL(b[idr]), a[l]), a[l]);
}
if(a[l] < a[r]) ans++; else ans--;
swap(a[l], a[r]);

printf("%lld\n", ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: