CodeForces 785E Anton and Permutation (分块)

来源:互联网 发布:淘宝最诚信的邮票商家 编辑:程序博客网 时间:2024/05/18 13:10

题意:初始是一个1-n的长度为n的有序数组,现在q次询问,每次询问交换a[l], a[r] 并且输出交换后整个数组有多少对逆序对(每次循环具有后效性)。1 ≤ n ≤ 200 000, 1 ≤ q ≤ 50 000


思路:第一个分块题,看到一篇讲的非常好的博客(戳这里),我写的话肯定没他写的好,,,

粘下他的思路吧:

当交换a[l]和a[r]时。讨论区间为(l,r),那么

ans=ans+a[r]a[l]+a[l]a[r]+(a[l]>a[r]?1:1)

所以问题就转化为如何求一个连续区间 (l,r) 内比给定值val小的元素个数。 
考虑分块。且块中元素保持有序,便于二分查询。 
1.若l==r,则ans不变。 
2.若l和r属于同一个块,可以 O(sqrt(n)) 扫描区间即可。 
3.若l和r不属于同一个块,先扫描区间 (l,b[l].r] 和 [b[r].l,r) 。然后 O(sqrt(n)log(sqrt(n))) 地计算出中间其他块小于 a[l] 或 a[r] 的元素。 
最坏情况下询问复杂度应该是 O(qsqrt(n)log(sqrt(n))) 
q=5104 , n=2105 , 最坏应该是 2108 。可以解决。

这道题可以使用分块查询的原因是每次更新时,最多只需要处理2个块,其他块中的信息能够以 O(log(sqrt(n))) 的复杂度快速获得。因此查询的复杂度从 O(n) 降到了 O(sqrt(n)log(sqrt(n))) 。这种算法可以推广到所有具有上述性质的问题。


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<vector>using namespace std;typedef long long ll;const int maxn = 2e5+5;const int maxsqrt = 505;int a[maxn], L[maxn], R[maxn], n, q, num;vector<int> blk[maxsqrt];void init(){    num = (int)sqrt(n);    for(int i = 0; i <= num+1; i++) blk[i].clear();    for(int i = 0; i < n/num; i++)        L[i] = num*i, R[i] = num*(i+1);    if(n%num) L[n/num] = n-(n%num), R[n/num] = n;    for(int i = 0; i < n; i++)        a[i] = i, blk[i/num].push_back(i);}int main(void){    while(cin >> n >> q)    {        init();        ll ans = 0;        while(q--)        {            int l, r;            scanf("%d%d", &l, &r);            l--, r--;            if(l == r) { printf("%I64d\n", ans); continue ; }            if(l > r) swap(l, r);            int idl = l/num, idr = r/num;            for(int i = idl+1; i < idr; i++)            {                int p = lower_bound(blk[i].begin(), blk[i].end(), a[l])-blk[i].begin();                ans -= p;                ans += blk[i].size()-p;                p = lower_bound(blk[i].begin(), blk[i].end(), a[r])-blk[i].begin();                ans += p;                ans -= blk[i].size()-p;            }            for(int i = l+1; i < R[idl] && i < r; i++)            {                if(a[i] > a[l]) ans++; else ans--;                if(a[i] > a[r]) ans--; else ans++;            }            for(int i = L[idr]; i < r && i > l; i++)            {                if(a[i] > a[l]) ans++; else ans--;                if(a[i] > a[r]) ans--; else ans++;            }            if(idl < idr)            {                blk[idl].erase(lower_bound(blk[idl].begin(), blk[idl].end(), a[l]));                blk[idl].insert(lower_bound(blk[idl].begin(), blk[idl].end(), a[r]), a[r]);                blk[idr].erase(lower_bound(blk[idr].begin(), blk[idr].end(), a[r]));                blk[idr].insert(lower_bound(blk[idr].begin(), blk[idr].end(), a[l]), a[l]);            }            if(a[l] < a[r]) ans++; else ans--;            swap(a[l], a[r]);            printf("%I64d\n", ans);        }    }    return 0;}


阅读全文
1 0
原创粉丝点击