BZOJ 3217: ALOEXT(块状链表+Trie树)

题目
又是一道分块踩爆 log ⁡ 2 \log^2 log2的经典题目。
因为有插入,用块状链表就行了。
对于每个块维护一个Trie树维护01串,一个SET维护次大值(其实是我懒得自己用分块写)。
Trie树这个东西其实对分块很不友好的,他修改查询都是 log ⁡ \log log,无法通过平衡分块复杂度来得到更好的结果。
修改直接插入块内的Trie O ( log ⁡ n ) O(\log n) O(logn)
询问暴力询问边角块 O ( n ) O(\sqrt n) O(n ),中间的跑Trie O ( n log ⁡ n ) O(\sqrt n\log n) O(n logn)
复杂度还可进一步改进。
设块的大小为 S S S
发现复杂度为 O ( log ⁡ n ) + O ( S ) + O ( n S log ⁡ n ) O(\log n) + O(S) + O(\frac nS \log n) O(logn)+O(S)+O(Snlogn)
显然修改复杂度太低况且如前文所说我们也没什么平衡它与询问复杂度的方法。
所以只需要考虑后面两项。
S = n log ⁡ n S = \sqrt{n\log n} S=nlogn 是取最值:
复杂度 O ( n n log ⁡ n ) O(n\sqrt {n\log n}) O(nnlogn )
log ⁡ 2 \log^2 log2快多了。
借鉴了一下dalao的博客。
目前2928msB站Rank1(让dalao获得了Rank2的好成绩真是对不起呢
AC Code:

#include<bits/stdc++.h>
#define maxn 200005
#define maxpt maxn * 60
#define S 655
using namespace std;

char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &res){
	char ch;
	for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}

int n,m,n0;
int id[maxn];
int ch[maxpt][2],siz[maxpt],tot;

void Insert_trie(int &now,int x,int v){
	if(!now) now = ++tot;
	for(int i=19,u=now;i>=0;i--){
		int &p = ch[u][(x>>i&1)];
		if(!p) p = ++tot;
		u = p;
		siz[u]+=v;
	}
}

struct block{
	int lb,rb;
	int a[S*2+10],rt,siz;
	multiset<int>st;
}B[maxn/S+1];
int fbl=1,cnt_bl=0;
multiset<int>::reverse_iterator it;

void Delete(int x){
	int bl = fbl;
	for(;B[bl].rb && B[bl].siz < x;x-=B[bl].siz,bl=B[bl].rb);
	B[bl].st.erase(B[bl].st.find(B[bl].a[x-1]));
	Insert_trie(B[bl].rt,B[bl].a[x-1],-1);
	for(int i=x-1;i<B[bl].siz-1;i++) B[bl].a[i] = B[bl].a[i+1];
	B[bl].siz--;
	if(!B[bl].siz){
		if(!B[bl].lb) fbl = B[bl].rb , B[fbl].lb = 0;
		else B[B[bl].lb].rb = B[bl].rb , B[B[bl].rb].lb = B[bl].lb;
	}
}

int seq[maxn],pre[maxn],suc[maxn],cnt=0;

int Query(int x,int y){
	int Bst=0,sst=0,lb=fbl,rb=fbl;
	for(;B[lb].rb && B[lb].siz<x;x-=B[lb].siz,lb=B[lb].rb);
	for(;B[rb].rb && B[rb].siz<y;y-=B[rb].siz,rb=B[rb].rb);
	//printf("%d %d %d %d\n",lb,rb,x,y);
		
	if(lb == rb){
		for(int i=x-1;i<y;i++)
		{
			if(B[lb].a[i] > Bst) sst = Bst , Bst = B[lb].a[i];
			else sst = max(sst , B[lb].a[i]);
			//printf("%d ",B[lb].a[i]);
		}
		//puts("");
		//printf("%d\n ",sst);
		int ret = 0;
		for(int i=x-1;i<y;i++){
			ret = max(ret , sst ^ B[lb].a[i]);
			//printf("%d ",sst ^ B[lb].a[i]);
		}
		//puts("");
		return ret;
	}
	else{
		for(int i=x-1;i<B[lb].siz;i++)
			if(B[lb].a[i] > Bst) sst = Bst , Bst = B[lb].a[i];
			else sst = max(sst , B[lb].a[i]);
		for(int i=0;i<y;i++)
			if(B[rb].a[i] > Bst) sst = Bst , Bst = B[rb].a[i];
			else sst = max(sst , B[rb].a[i]);
		cnt = 0;
		for(int i=B[lb].rb;i!=rb;i=B[i].rb){
			it = B[i].st.rbegin();
			if(it!=B[i].st.rend()){
				if((*it) > Bst) sst = Bst , Bst = (*it);
				else sst = max(sst , (*it));
				it++;
				if(it!=B[i].st.rend()){
					if((*it) > Bst) sst = Bst , Bst = (*it);
					else sst = max(sst , (*it));
				}
			}
			seq[++cnt] = B[i].rt;
			pre[cnt] = cnt-1 , suc[cnt-1] = cnt;
		}	
		suc[cnt] = cnt+1;
		
		int ret = 0;
		if(cnt)
		{
			ret = sst;
			for(int i=19;i>=0;i--){
				bool flag = 0 , p = ((sst>>i&1)^1);
				//printf("%d\n",);
				for(int j=suc[0];j!=cnt+1;j=suc[j])
				{
					//printf("%d\n",siz[ch[seq[j]][p]]);
					if(siz[ch[seq[j]][p]]) flag = 1;
				}
				if(flag){
					for(int j=suc[0];j!=cnt+1;j=suc[j]){
						seq[j] = ch[seq[j]][p];
						if(!seq[j])
							pre[suc[j]] = pre[j],
							suc[pre[j]] = suc[j];
					}
					ret ^= (1<<i) * p;
				}
				else{
					for(int j=suc[0];j!=cnt+1;j=suc[j]){
						seq[j] = ch[seq[j]][!p];
						if(!seq[j])
							pre[suc[j]] = pre[j],
							suc[pre[j]] = suc[j];
					}
					ret ^= (1<<i) * (!p);
				} 
			}
		}
		for(int i=x-1;i<B[lb].siz;i++)
			ret = max(ret , B[lb].a[i]^sst);
		for(int i=0;i<y;i++)
			ret = max(ret , B[rb].a[i]^sst);
		return ret;
	}
}

void split(int x){
	B[++cnt_bl].lb=x,B[cnt_bl].rb=B[x].rb;
	B[B[x].rb].lb=cnt_bl,B[x].rb=cnt_bl;
	B[x].siz-=S,B[cnt_bl].siz=S;
	memcpy(B[cnt_bl].a,B[x].a+B[x].siz,S*sizeof(int));
	for(int i=0;i<S;i++)
		Insert_trie(B[cnt_bl].rt,B[cnt_bl].a[i],1),
		Insert_trie(B[x].rt,B[cnt_bl].a[i],-1),
		B[cnt_bl].st.insert(B[cnt_bl].a[i]),
		B[x].st.erase(B[x].st.find(B[cnt_bl].a[i]));
}

void Insert(int x,int y){
	int lb = fbl;
	for(;B[lb].rb && B[lb].siz < x;x-=B[lb].siz,lb=B[lb].rb);
	for(int i=B[lb].siz;i>x;i--) B[lb].a[i] = B[lb].a[i-1];
	B[lb].siz++;
	B[lb].a[x]=y;
	B[lb].st.insert(y);
	Insert_trie(B[lb].rt,y,1);
	
	if(B[lb].siz >= 2 * S)
		split(lb);
}

void Modify(int x,int y){
	int lb = fbl;
	for(;B[lb].rb && B[lb].siz < x;x-=B[lb].siz,lb=B[lb].rb);
	//printf("%d\n",x);
	int py = B[lb].a[x-1];B[lb].a[x-1] = y;
	//for(multiset<int>::iterator it=B[lb].st.begin();it!=B[lb].st.end();it++)
	//	printf("%d ",*it);
	//puts("");
	//printf("%d\n",B[lb].st.count(py));
	B[lb].st.erase(B[lb].st.find(py));
	B[lb].st.insert(y);
	Insert_trie(B[lb].rt,py,-1);
	Insert_trie(B[lb].rt,y,1);
}

int main(){
	
	//int t1=clock();
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	
	read(n),read(m);n0 = n;
	for(int i=0,x;i<n;i++){
		read(x);
		B[i/S+1].a[B[i/S+1].siz] = x;
		Insert_trie(B[i/S+1].rt,x,1),
		B[i/S+1].st.insert(x);	
		B[i/S+1].siz ++;
	}
	cnt_bl = (n-1)/S+1;
	for(int i=2;i<=cnt_bl;i++)
		B[i-1].rb = i , 
		B[i].lb = i-1 ;
	
	char s[2];
	for(int x,y,la=0;m--;){
		for(;!isalpha(s[0]=getc()););
		//puts("1");
		//puts(s);
		if(s[0] == 'D'){
			read(x);
			x=(x+la) % n0;
			//for(int i=0;i<B[fbl].siz;i++)
			//	printf("%d ",B[fbl].a[i]);puts("");
			//printf("%d\n",x+1);
			Delete(x+1);
			n0--;
		}
		else{
			read(x),read(y);
			if(s[0] == 'F'){
				x=(x+la) % n0 , y=(y+la) % n0;
				//for(int i=0;i<B[2].siz;i++)
					printf("%d ",B[2].a[i]);puts("");
				//for(int j=fbl;j;j=B[j].rb)
				//for(int i=0;i<B[j].siz;i++)
				//	printf("%d ",B[j].a[i]);
				//puts("");
				//printf("%d %d\n",x+1,y+1);
				printf("%d\n",la=Query(x+1,y+1));
			}
			else {
				x=(x+la) % n0 , y=(y+la) % 1048576;
				//printf("%d\n",fbl);
				//	for(int i=0;i<B[j].siz;i++)
				//		printf("%d ",B[j].a[i]);puts("");
				//printf("%d %d\n",x+1,y);
				if(s[0] == 'I') n0 ++ , Insert(x,y);
				else Modify(x+1,y);
			}
		}
	}
	//freopen("CON","w",stdout);
	//printf("%d\n",clock()-t1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值