CF1093E 题解

来一发 \(O(n \sqrt n)\) 时间,\(O(n)\) 空间的分块写法。

首先建模,把 数值 \(x\) 在两个数组中出现的位置作为坐标,问题就转化为一个二维动态数点。

考虑用序列分块维护第一维,第二维用 值域分块 维护,这样子平衡复杂度玩就得到一个 \(O(n \sqrt n)\) 时间的做法,但是空间很大。

考虑到块与块之间并无联系,所以考虑 逐块处理 也就是说把每个块的修改与贡献离线下来分开计算,那么空间就被优化到了 \(O(n)\)

综上,我们就可以写出代码了。

#include<bits/stdc++.h>
#define int long long
//#define lowbit(x) (x&-(x))
using namespace std;
const int maxn = 6e5+114;
const int maxsq = 500;
const int warma = 447;
int n,cnt;
struct Node{
    int opt,x,l,r,L,R;
}Q[maxn];
int anser[maxn];
pair<int,int> wyb[maxn],zbz[maxn];//处理时的数组 & 原本的数组
int val(int l1,int r1,int l2,int r2){//计算两个区间的交集大小
    int mxl=max(l1,l2),mir=min(r1,r2);
    if(mxl>mir) return 0;
    else return (mir-mxl+1);
}
class block{//O(\sqrt n) 区间修改 O(1) 区间查询 
	private:
		int bl_pre[maxsq][maxsq];//块内前缀和
		int tag[maxsq];//块内标记 
		int pre[maxsq];//块间前缀和
	public:
		void add(int l,int r,int v);
		int query(int l,int r);
        void init();
}chifan;
void block::init(){
    for(int i=0;i<maxsq;i++)
        for(int j=0;j<maxsq;j++)
            bl_pre[i][j]=tag[i]=pre[i]=0;
}
void block::add(int l,int r,int v){
	int bl=l/warma;
	int lpos=l%warma;
	if(lpos==0){
		lpos=warma;
		bl--;
	}
	int br=r/warma;
	int rpos=r%warma;
	if(rpos==0){
		rpos=warma;
		br--;
	}
	//整块处理 
    if(bl==br){
        for(int i=lpos;i<=rpos;i++){
            bl_pre[bl][i]+=v*(i-lpos+1);
        }
        for(int i=rpos+1;i<=warma;i++){
            bl_pre[bl][i]+=v*(rpos-lpos+1);
        }
        pre[0]=bl_pre[0][warma];
	    for(int i=1;i<=warma;i++){
		    pre[i]=pre[i-1]+bl_pre[i][warma]+tag[i]*warma;
	    }
        return ;
    }
	for(int i=bl+1;i<=br-1;i++){
		tag[i]+=v;
	}
	//头部残块处理
	for(int i=lpos;i<=warma;i++){
		bl_pre[bl][i]+=v*(i-lpos+1); 
	}
	//尾部残块处理
	for(int i=1;i<=rpos;i++){
		bl_pre[br][i]+=v*i;
	}
	for(int i=rpos+1;i<=warma;i++){
		bl_pre[br][i]+=v*rpos;
	}
	//块间处理
	pre[0]=bl_pre[0][warma];
	for(int i=1;i<=warma;i++){
		pre[i]=pre[i-1]+bl_pre[i][warma]+tag[i]*warma;
	} 
    return ;
}
int block::query(int l,int r){
    int bl=l/warma;
	int lpos=l%warma;
	if(lpos==0){
		lpos=warma;
		bl--;
	}
	int br=r/warma;
	int rpos=r%warma;
	if(rpos==0){
		rpos=warma;
		br--;
	}
    if(bl==br){
        return bl_pre[bl][rpos]-bl_pre[bl][lpos-1]+tag[bl]*(rpos-lpos+1);
    }
    int res=0;
    res+=pre[br-1]-pre[bl];
    res+=bl_pre[bl][warma]-bl_pre[bl][lpos-1]+(warma-lpos+1)*tag[bl];
    res+=bl_pre[br][rpos]+tag[br]*rpos;
    return res;
}
void work(int lt,int rt){//逐块处理
    rt=min(rt,n);
    chifan.init();
    for(int i=1;i<=n;i++) wyb[i]=zbz[i];
    for(int i=lt;i<=rt;i++){
        chifan.add(wyb[i].first,wyb[i].second,1);
    }
    for(int i=1;i<=cnt;i++){
        if(Q[i].opt==1){
            int l=Q[i].l,r=Q[i].r,L=Q[i].L,R=Q[i].R;
            if(l<=lt&&rt<=r){//被包含
                anser[i]+=chifan.query(L,R);
            }
            else if(lt<=l&&r<=rt){//另外一种被包含
                int res=0;
                for(int i=l;i<=r;i++){
                    res+=val(wyb[i].first,wyb[i].second,L,R);
                }
                anser[i]+=res;
            }
            else if(rt>=r&&r>=lt){
                int res=0;
                for(int i=lt;i<=r;i++){
                    res+=val(wyb[i].first,wyb[i].second,L,R);
                }
                anser[i]+=res;
            }
            else if(lt<=l&&l<=rt){
                int res=0;
                for(int i=l;i<=rt;i++){
                    res+=val(wyb[i].first,wyb[i].second,L,R);
                }
                anser[i]+=res;
            }
        }
        else{
            int x=Q[i].x,l=Q[i].l,r=Q[i].r;
            if(lt<=x&&x<=rt){
                chifan.add(wyb[x].first,wyb[x].second,-1);
                wyb[x].first=l,wyb[x].second=r;
                chifan.add(wyb[x].first,wyb[x].second,1);
            }
        }
    }
}
int sq;
int q;
int a[maxn],b[maxn];
int A[maxn],B[maxn];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>q;
	sq=sqrt(n);
	for(int i=1;i<=n;i++){
		cin>>a[i];
		A[a[i]]=i;
	}
	for(int i=1;i<=n;i++){
		cin>>b[i];
		B[b[i]]=i;
	}
	for(int i=1;i<=n;i++){
		zbz[A[i]].first=B[i];
		zbz[A[i]].second=B[i];
	}
	for(int i=1;i<=q;i++){
		int OPT;
		cin>>OPT;
		if(OPT==1){
			int la,ra,lb,rb;
			cin>>la>>ra>>lb>>rb;
			cnt++;
			Q[cnt].opt=1;
			Q[cnt].l=la;
			Q[cnt].r=ra;
			Q[cnt].L=lb;
			Q[cnt].R=rb;
		}
		else{
			int x,y;
			cin>>x>>y;
			//b[x] - A[b[x]] x -> A[b[x]] y
			//b[y] - A[b[y]] y -> A[b[y]] x
			//b[x] - b[y]
			//B[b[x]]
			cnt++;
			Q[cnt].opt=2;
			Q[cnt].x=A[b[x]];
			Q[cnt].l=y;
			Q[cnt].r=y;
			cnt++;
			Q[cnt].opt=2;
			Q[cnt].x=A[b[y]];
			Q[cnt].l=x;
			Q[cnt].r=x;
			swap(b[x],b[y]);
			swap(B[b[x]],B[b[y]]);
		}
	}
	int L=1,R=sq;
	while(L<=n){
    	work(L,R);
   		L+=sq,R+=sq;
	}
	for(int i=1;i<=cnt;i++){
    	if(Q[i].opt==1) cout<<anser[i]<<'\n';
	}
}
/*
6 2
5 1 4 2 3 6
2 5 3 1 4 6
2 2 4
1 2 3 3 5
*/

题外话:这一道题我口胡过一个线段加和一个二维数最大值的加强版(而且写出来了,这题代码就是这么改出来的)。

posted @ 2024-01-30 23:57  ChiFAN鸭  阅读(7)  评论(0编辑  收藏  举报