首页 > 其他分享 >CF455D Serega and Fun 题解

CF455D Serega and Fun 题解

时间:2024-07-31 20:52:13浏览次数:13  
标签:Serega int 题解 top pos -- maxn Fun 碎块

Before it

来当一回教练的题解翻译家,平衡树这种高级算法自然是不会的,所以详细讲一下STL。

成为蒟蒻(也就是自己)的福音。

Solution

我们观察到题目要求“把第 \(r\) 个数插入在第 \(l\) 个数之前,其他数顺序不变“,使用 \(deque\) 的\(push\)_\(front\) 和 \(push\) _ $ back$ 操作可以轻而易举的实现。

现在考虑分块,对于每一块维护一个\(deque\) ,$q_{i,j} $ 表示第 \(i\) 块,第 \(j\) 位的值是多少,同时对于每一块开一个桶数组,\(tot_{i,j}\) 维护第 \(i\) 块有多少个 \(j\)。

这里详细讲一下如何处理操作。

  1. 初始化

    请参考数列分块9题,维护每个块的开头,结尾,以及 \(i\) 在哪个块。(作者使用 \(pos\) 数组。

  2. 移动

    对于在同一个块的情况,暴力修改即可。可以开一个栈辅助转移(当然啦你不开也可以。

    对于不在同一个块的情况,求出左碎块和右碎块的大小,我们先把左碎块的值存到栈里,然后将其直接删去。然后找到被往前移的那个加到栈里,然后再讲左碎块填满,此时栈里还剩一个元素。

    对于中间的整块,实际上也就是元素都往后移动一个,可以在这个块的 \(deque\) 数组里 \(push\)_ \(front\) 上一个块遗留下来的最后一个值,然后在把最后一个元素 \(pop\)_\(back\) 走,把它存到栈里转移到下一个块。

    对于右碎块,我们先把右碎块里的值依次存入栈里,扔掉栈顶元素(也就是被往前移动的那个),最后再依次将右碎块补满即可。

    注意在转移的过程中,注意 \(tot\) 也需要同步转移。

  3. 求出区间 \(l--r\) 中 \(k\) 的值

    对于在同一个块的情况,直接暴力计算即可。

    对于左右碎块,求出长度和起终点,暴力计算。这里注意端点的细节!(作者写错这里调了很久...

    对于中间的块,计算桶的答案。

至此,本题得到解决。

时间复杂度 \(O(n\sqrt{n})\)。但是因为STL常数很大所以跑得很慢...

Code

代码
//分块题,并不是神秘线段树
//对于每个块维护一个deque  用来支持1操作
//维护一个桶,便于查询 
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,blen,a[maxn],op,l,r,k,s[maxn];//s数组是手写栈,为了方便转移操作的 
int pos[maxn],st[maxn],ed[maxn],tot[320][maxn];//tot[i][j]表示第i块有多少个j 
deque<int> q[320]; //和vector类似,可以使用下标访问 
void init(){
	blen=sqrt(n);
	int t=n/blen;
	if(n%blen)t++;
	for(int i=1;i<=t;i++){
		st[i]=ed[i-1]+1;
		ed[i]=ed[i-1]+blen;
	}
	ed[t]=n;
	for(int i=1;i<=n;i++){
		pos[i]=(i-1)/blen+1;
		tot[pos[i]][a[i]]++;
		q[pos[i]].push_back(a[i]);
	}
}
void modify(int l,int r){
	int top=0;
	if(pos[l]==pos[r]){
		int now=pos[l];
		l-=st[now],r-=st[now],s[++top]=q[now][r];
		for(int i=l;i<r;i++) s[++top]=q[now][i];
		for(int i=r;i>=l;i--) q[now][i]=s[top--];
		return;
	}
	int cnt1=ed[pos[l]]-l+1,cnt2=r-st[pos[r]]+1;
	while(cnt1--){
		int x=q[pos[l]].back();
		s[++top]=x;
		tot[pos[l]][x]--;
		q[pos[l]].pop_back();
	}
	s[++top]=q[pos[r]][cnt2-1];//被往前移的那个
	while(top>1){
		int x=s[top];
		q[pos[l]].push_back(x);
		tot[pos[l]][x]++;
		top--;
	} 
	for(int i=pos[l]+1;i<=pos[r]-1;i++){//处理整块 往后移动一个 
		int x=s[top];
		q[i].push_front(x);
		tot[i][x]++,top--;
		int y=q[i].back();
		tot[i][y]--;
		s[++top]=y;
		q[i].pop_back();
	}
	while(cnt2--){
		int x=q[pos[r]].front();
		s[++top]=x;
		tot[pos[r]][x]--,q[pos[r]].pop_front();
	}
	top--;
	while(top){
		int x=s[top];
		q[pos[r]].push_front(x);
		tot[pos[r]][x]++;
		top--;
	}
}
int query(int l,int r,int k){
	int ans=0;
	if(pos[l]==pos[r]){
		int now=pos[l];
		l-=st[now],r-=st[now];
		for(int i=l;i<=r;i++){
			if(q[now][i]==k) ans++;
		}
		return ans;
	}
	int cnt1=ed[pos[l]]-l+1,cnt2=r-st[pos[r]]+1;
	//处理左碎块 
	for(int i=q[pos[l]].size()-cnt1;i<=q[pos[l]].size()-1;i++){
		if(q[pos[l]][i]==k) ans++;
	} 
//	//处理右碎块
	for(int i=0;i<=cnt2-1;i++){
		if(q[pos[r]][i]==k) ans++;
	} 
//	cout<<"Aapwp"<<ans<<endl;
	for(int i=pos[l]+1;i<=pos[r]-1;i++){
		ans+=tot[i][k];
	}
//	cout<<"Aapwp"<<ans<<endl;
	return ans;
}

int main(){
	ios::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	init();
	cin>>m;
	int lans=0;
	while(m--){
		cin>>op>>l>>r;
		l=((lans+l-1)%n)+1;
		r=((lans+r-1)%n)+1;
		if(l>r) swap(l,r);
		if(op==1){
			modify(l,r);	
		}
		else{
			cin>>k;
			k=((lans+k-1)%n)+1;
			lans=query(l,r,k);
			cout<<lans<<endl;
		}
	}
}

标签:Serega,int,题解,top,pos,--,maxn,Fun,碎块
From: https://www.cnblogs.com/wann-042013/p/18335448

相关文章

  • 暗区突围pc端下载失败/卡正在初始化/连接伺服务器失败/问题解决方法
    暗区突围pc端下载失败/卡正在初始化/连接伺服务器失败/问题解决方法暗区突围pc端下载失败/卡正在初始化/连接伺服务器失败/问题解决方法暗区突围也可以在电脑上游玩拉,暗区突围PC端上线在即,本次上线就是全球抢先测试了,很多小伙伴在游戏下载过程中遇到了很多问题,比如:下载失......
  • QOJ6504 Flower‘s Land 2 题解
    QOJ6504Flower'sLand2题解题目链接:QOJ6504Flower'sLand2题意:给定一个只包含\(0,1,2\)的序列,\(T\)次询问,询问有两种:区间所有数加\(1\)然后模\(3\)求一段区间能否通过每次删掉相邻两个相同的数删完(如\(1,0,0,2,2,1\)就满足条件)题解:考虑用什么方法来维护区间......
  • CF1995C Squaring 题解
    思路详解:请注意,本题解用到了非整数计算,也就是说性能可能不如整数运算,但是易于实现,追求最优解的大佬不建议观看本题解。这个题看似简单,但是由于涉及到了平方操作,不用高精度根本存不下,然后如果你要用高精度的话又会T......
  • 关于题解
    这里说一下为什么要在博客园写东西,其实有几个主要原因:首先是我一个朋友写题解的时候,因为多了一个空格被打回。然后我这个朋友就开始在这里写东西了。然后这个朋友找到了一个拿过金牌的学长,他同样之前审过题解,总之他认为只要不是题解写的完全不能看,或者在某些地方有一些事实性错......
  • 平行四边形 题解
    题目id:20306题目描述鱼大大凭借着优秀的语文成绩当上了数学课代表?!鱼大大心想着数学和我语文好也不搭边呀,不过他的数学老师疯狂给鱼大大画饼:只要你当了数学课代表,有很多很多权利的啦......最后数学老师告诉鱼大大,人只要一行行,行行行,这句话在学科上也是一样的,语文学的好,数学也一......
  • funccache:革命性的Python函数缓存工具,轻松提升代码效率!
    funccacheEnglish|中文如其名,funccache实现函数缓存功能,由GQYLPY团队研发的一个框架,可缓存某个函数或某个类中定义的所有方法的返回值。你的程序中有一个函数会被多次调用,并且返回值不变,你会怎么做?为提高代码效率,你会先调用一次该函数并把返回值存到一个变量,之后就使用......
  • Python - Functional programming
    Functionalprogrammingisaprogrammingparadigminwhichmostoftheworkinaprogramisdoneusingpurefunctions.Apurefunctionisafunctionwithoutanysideeffects;itsreturnvalueisalwaysdeterminedbyitsinputarguments,soitalwaysreturn......
  • Python - Creating jump tables using lambda functions
    Wecanplacelambdafunctioninsidelistanddictionaryliterals.Thiswaywecanuselambdaexpressionstocreatejumptables.>>>L=[lambdas:s.strip().lower(),... lambdas:s.strip().upper(),... lambdas:s.lstrip().title(),... lambd......
  • 数字检测 题解
    题目id:20317题目描述作为一个学渣的鱼大大在学习了进制数之后,经常会写错进制数,导致他在做题的时候经常出现,写到了最后发现数字是错的情况,非常浪费时间。所以他迫切地想要一位大聪明随时随刻能帮他检测一下他写的\(n\)进制数到底是不是对的。现在鱼大大给出了一个\(n\)进制的数\(......
  • 题解_P2024 [NOI2001] 食物链
    [NOI2001]食物链题目描述动物王国中有三类动物\(A,B,C\),这三类动物的食物链构成了有趣的环形。\(A\)吃\(B\),\(B\)吃\(C\),\(C\)吃\(A\)。现有\(N\)个动物,以\(1\simN\)编号。每个动物都是\(A,B,C\)中的一种,但是我们并不知道它到底是哪一种。有人用两种说法对这......