CF785E Anton and Permutation(分块)

这道题本质上是一个二维数点的模板,并且是强制在线的,因此可以用树套树,但是我不会树套树

可以想到一个暴力的方法,就是分块,分完块后,每块动态维护一个vector,因为我们发现,交换两个数后,只有在l-r区间内并且范围在a[l]-a[r]之间的数才会收到影响

这样我们就可以通过vector查找范围

分块这东西,还是很牛逼的,因为可以发现,每块不超过sqrt(n)并且块的数量也不超过他

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<string>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int mod=1e9+7;
vector<int> num[10005];
int n;
int a[N];
int block;
void init(){
    block=sqrt(n);
    for(int i=1;i<=n;i++){
        a[i]=i;
        int pos=(i-1)/block+1;
        num[pos].push_back(i);
    }
}
ll work(int l,int r){
    if(l==r)
        return 0;
    int idx1=(l-1)/block+1;
    int idx2=(r-1)/block+1;
    int x=a[l],y=a[r];
    int pos=find(num[idx1].begin(),num[idx1].end(),x)-num[idx1].begin();
    num[idx1][pos]=y;
    pos=find(num[idx2].begin(),num[idx2].end(),y)-num[idx2].begin();
    num[idx2][pos]=x;
    sort(num[idx1].begin(),num[idx1].end());
    sort(num[idx2].begin(),num[idx2].end());
    ll ans=0;
    int f;
    if(x>y){
        swap(x,y);
        f=-1;
    }
    else{
        f=1;
    }
    int i;
    if(idx1==idx2){
        for(i=l+1;i<r;i++){
            if(a[i]>x&&a[i]<y)
                ans++;
        }
    }
    else{
        for(i=l+1;i<=idx1*block;i++)
            if(a[i]>x&&a[i]<y)
                ans++;
        for(i=idx1+1;i<idx2;i++){
            ans+=upper_bound(num[i].begin(), num[i].end(), y) - lower_bound(num[i].begin(), num[i].end(), x);
        }
        for(i=(idx2-1)*block+1;i<r;i++)
            if(a[i]>x&&a[i]<y)
                ans++;
    }
    swap(a[l],a[r]);
    return (2*ans+1)*f;
}
int main(){
    int q;
    cin>>n>>q;
    ll ans=0;
    init();
    while(q--){
        int l,r;
        cin>>l>>r;
        if(l>r)
            swap(l,r);
        ans+=work(l,r);
        cout<<ans<<endl;
    }
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12759051.html