首页 > 其他分享 >【OI】随机数据下根号树的平替实现

【OI】随机数据下根号树的平替实现

时间:2023-01-18 21:01:00浏览次数:36  
标签:suf 平替 OI int res1 maxw sqrt res2 根号

原理

在随机数据下,把原序列分成 \(\sqrt n\) 个块,维护每个块的前缀后缀最大值,那么,在随机询问下,对于在一个块中的询问,暴力查询。

复杂度

概率 \(\sqrt n ^ {-1}\) ,复杂度 \(O(\sqrt n)\) ,均摊 \(O(1)\) 。

对于在不同块中的询问,对连续块询问以及散块前缀后缀最大值查询。

如何查询连续块

再用一遍上面的方法,对于块内最大值构成的序列二次分块,照相同办法处理,而这一次的连续块可以直接 \(O(\sqrt n )\) 暴力处理。

复杂度

随机数据下:

建表 : \(O(n)\)

查询 : \(O(1)\)

单点修改 :\(O(\sqrt n)\) (单点修改只需重建一个大小为 \(O(\sqrt n)\) 的表和一个块内前缀后缀最大值即可,而表可以暴力重建,块也只用扫一遍)

代码 (由乃救爷爷)

#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int maxn = 5e3 + 10;
const int warma = 5e3;
const int maxw = 70;
const int Warma = 62;
int lg[maxn];
int cntsum,n,q,cnt;
int pre[maxw][maxw],suf[maxw][maxw];
int bye[maxw][maxw];
int maxans[maxw][maxw];
int seed,sumcnt=0;
namespace GenHelper
{
    unsigned z1,z2,z3,z4,b;
    unsigned rand_()
    {
    b=((z1<<6)^z1)>>13;
    z1=((z1&4294967294U)<<18)^b;
    b=((z2<<2)^z2)>>27;
    z2=((z2&4294967288U)<<2)^b;
    b=((z3<<13)^z3)>>21;
    z3=((z3&4294967280U)<<7)^b;
    b=((z4<<3)^z4)>>12;
    z4=((z4&4294967168U)<<13)^b;
    return (z1^z2^z3^z4);
    }
}
void srand(unsigned x)
{using namespace GenHelper;
z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51;}
int read()
{
    using namespace GenHelper;
    int a=rand_()&32767;
    int b=rand_()&32767;
    return a*32768+b;
}
class chunking{
	public:
	int b[maxn];
	int pre[maxn];
	int suf[maxn];
	inline void maintain();
	inline int ask(int l,int r);
	int length;
	int anser;
}block[maxn];
inline void handle(){
	int res1=1,res2=1;
	for(int i=1;i<=cntsum;i++){
		if(res1>Warma) res1=1,res2++;
		bye[res1][res2]=block[i].anser;
		res1++;
	}
	cnt=res2;
	for(int i=1;i<=cnt;i++){
		pre[1][i]=bye[1][i];
		for(int j=2;j<=Warma;j++){
			pre[j][i]=max(pre[j-1][i],bye[j][i]);
		}
		suf[Warma][i]=bye[Warma][i];
		for(int j=Warma-1;j>=1;j--){
			suf[j][i]=max(suf[j+1][i],bye[j][i]);
		}
	}
	for(int i=1;i<=cnt;i++){
		maxans[i][i]=0;
		for(int j=1;j<=Warma;j++){
			maxans[i][i]=max(maxans[i][i],bye[j][i]);
		}
	}
	for(int i=1;i<=cnt;i++){
		for(int j=i+1;j<=cnt;j++){
			maxans[i][j]=max(maxans[i][j-1],maxans[j][j]);
		}
	}
}
inline int question(int l,int r){
	int lc = l/Warma+1;
	l%=Warma;
	if(l==0) l=Warma,lc--;
	int rc= r/Warma+1;
	r%=Warma;
	if(r==0) r=Warma,rc--;
	if(lc==rc){
		int res=0;
		for(int i=l;i<=r;i++){
			res=max(res,bye[i][lc]);
		}
		return res;
	}
	if(lc==rc+1){
		return max(suf[l][lc],pre[r][rc]);
	}
	else
	{
		int res = maxans[lc+1][rc-1];
		res=max(res,max(suf[l][lc],pre[r][rc]));
		return res;
	}
}
inline void chunking::maintain(){
	anser=0;
	pre[1]=b[1];
	anser=max(anser,b[1]);
	for(int i=2;i<=length;i++) pre[i]=max(pre[i-1],b[i]),anser=max(anser,b[i]);
	suf[length]=b[length];
	for(int i=length-1;i>=1;i--) suf[i]=max(suf[i+1],b[i]);
}
inline int chunking::ask(int l,int r){
	 int res=0;
	 for(int i=l;i<=r;i++) res=max(res,b[i]);
	 return res;
}
inline int query(int l,int r){
	int lc=l/warma+1;
	l%=warma;
	if(l==0) lc--,l+=warma;
	int rc=r/warma+1;
	r%=warma;
	if(r==0) rc--,r+=warma;
	if(lc==rc){
		return block[lc].ask(l,r);
	}
	if(lc+1==rc){
		return max(block[lc].suf[l],block[rc].pre[r]);
	}
	else
	{
		int res=question(lc+1,rc-1);
		res=max(res,max(block[lc].suf[l],block[rc].pre[r]));
		return res;
	}
}
inline void change(int x,int val){
	int xc=x/warma+1;
	x%=warma;
	if(x==0) xc--,x+=warma;
	block[xc].b[x]=val;
	for(int i=xc;i<=xc;i++) block[i].maintain();
	handle();
}
inline void inti(){
	for(int i=1;i<=maxn-10;i++){
		lg[i]=log2(i);
	}
	cin>>n>>q>>seed;
	srand(seed);
	//seed=read();
	int res1=1,res2=1;
	for(int i=1;i<=n;i++){
		if(res1>warma) block[res2].length=res1-1,res1-=warma,res2++;
		block[res2].b[res1]=read();
		//cout<<chifan()<<' ';
		res1++;
	}
	block[res2].length=res1-1;
	cntsum=res2;
	for(int i=1;i<=cntsum;i++) block[i].maintain();
	handle();
}
int anser;
signed main(){
	//freopen("5.in","r",stdin);
	//freopen("5.out","w",stdout);
	inti();
	while(q--){
		int op;
		op = 1;
		if(op==1){
			int l,r;
			l=read()%n+1;
			r=read()%n+1;
			if(l>r) swap(l,r);
			//cout<<query(l,r)<<'\n';
			anser+=query(l,r);
		}
		if(op==2){
			int x,val;
			x=read();
			val=read();
			change(x,val);
		}
	}
	cout<<anser;
}

标签:suf,平替,OI,int,res1,maxw,sqrt,res2,根号
From: https://www.cnblogs.com/chifan-duck/p/17060560.html

相关文章