其他分享
首页 > 其他分享> > P7708「Wdsr-2.7」八云蓝自动机 Ⅰ

P7708「Wdsr-2.7」八云蓝自动机 Ⅰ

作者:互联网

*X. P7708「Wdsr-2.7」八云蓝自动机 Ⅰ

摘自 分治与根号数据结构学习笔记 第三部分 莫队 例题 X.。

一道莫队好题。私以为本题最有价值的地方在于对单点修改的转化以及对交换两个数的处理:需要维护原来每个位置现在的位置,以及现在每个位置原来的位置。

注意到这个单点修改并不方便实现(如果是单点加就好做了),我们可以使用一个小技巧将其转化为交换两个数,即新建一个 \(a_c=k\),并将其看做 \(a_x\) 与 \(a_c\) 交换。这一步非常巧妙,因为它消灭了单点修改这一麻烦的操作。

对于多次询问一段区间的操作结果,我们通常需要使用莫队实现,因此考虑区间在伸缩时需要维护什么东西。为了支持在操作序列最前面加入交换两个数的操作,我们不难想到维护:

右端点左移和左端点右移的情况分别与上述两种情况相似,不再赘述。时间复杂度 \(\mathcal{O}(n\sqrt n)\)。

const int N=4e5+5;
const int B=666;
uint n,m,q,cnt,a[N],id[N],op[N],x[N],y[N];
struct query{
	int l,r,blk,id;
	bool operator < (const query &v) const {
		return blk!=v.blk?blk<v.blk:blk&1?r>v.r:r<v.r; 
	}
}c[N];

uint ans,res[N],pos[N],rev[N],add[N];
int main(){
	cin>>n>>m,cnt=n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=m;i++){
		cin>>op[i]>>x[i]; if(op[i]!=3)cin>>y[i];
		if(op[i]==1)a[++cnt]=y[i],op[i]=2,y[i]=cnt;
	}
	for(int i=1;i<=cnt;i++)pos[i]=rev[i]=i;
	cin>>q;
	for(int i=1,l,r;i<=q;i++)cin>>l>>r,c[i]={l,r,l/B,i};
	sort(c+1,c+q+1);
	for(int i=1,l=1,r=0;i<=q;i++){
		while(r<c[i].r){
			r++;
			if(op[r]==2){
				swap(pos[x[r]],pos[y[r]]),swap(a[x[r]],a[y[r]]);
				swap(rev[pos[x[r]]],rev[pos[y[r]]]);
			}
			else ans+=a[x[r]],add[pos[x[r]]]++;
		}
		while(l>c[i].l){
			l--;
			if(op[l]==2){
				uint del=a[rev[y[l]]]-a[rev[x[l]]];
				swap(rev[x[l]],rev[y[l]]),ans+=(add[x[l]]-add[y[l]])*del;
				swap(a[rev[x[l]]],a[rev[y[l]]]);
				swap(pos[rev[x[l]]],pos[rev[y[l]]]),swap(add[x[l]],add[y[l]]);
			}
			else ans+=a[rev[x[l]]],add[x[l]]++;
		}
		while(r>c[i].r){
			if(op[r]==2){
				swap(pos[x[r]],pos[y[r]]),swap(a[x[r]],a[y[r]]);
				swap(rev[pos[x[r]]],rev[pos[y[r]]]);
			}
			else ans-=a[x[r]],add[pos[x[r]]]--;
			r--;
		}
		while(l<c[i].l){
			if(op[l]==2){
				uint del=a[rev[y[l]]]-a[rev[x[l]]];
				swap(rev[x[l]],rev[y[l]]),ans+=(add[x[l]]-add[y[l]])*del;
				swap(a[rev[x[l]]],a[rev[y[l]]]);
				swap(pos[rev[x[l]]],pos[rev[y[l]]]),swap(add[x[l]],add[y[l]]);
			}
			else ans-=a[rev[x[l]]],add[x[l]]--;
			l++;
		}
		res[c[i].id]=ans;
	}
	for(int i=1;i<=q;i++)cout<<res[i]<<"\n";
	return 0;
}

标签:Wdsr,int,rev,add,pos,八云,swap,2.7,op
来源: https://www.cnblogs.com/alex-wei/p/Luogu_P7708.html