其他分享
首页 > 其他分享> > 带插入区间K小值

带插入区间K小值

作者:互联网

link

题意很明了,就是题目,只不过题目中没说这道题强制在线。

普通情况下可以用平衡树套权值线段树,或者用线段树(树状数组)套个位置平衡树(但我不会写也没有写过)。然而我浏览了一圈讨论之后发现万恶的noip似乎卡了树套树的写法。于是迫不得已学了下块状链表。

块状链表说起来并没有太难,思想很简易,只是代码细节特别多,这也导致我今天下午从三点半开始写一直写到了现在,也就是接近六点。各种bug层出不穷,实在令人感动。主要是查询时for循环里的开关不能取等,然后跳出来后只需自减一次即可。

这道题还用了值域分块,与块状链表一起逼得我不得不小小滴压了压行。

人都写麻了。

#include<cstdio>
#include<cmath>
//#define zczc
const int N=70010;/*值域*/const int S=350;/*值域块数*/const int ks=S;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}wh*=f;return;
}
struct node{int a[S<<1];/*块内数*/int s1[N];/*块间数值前缀和*/int s2[S];/*块间值域块前缀和*/int size,l,r;}a[S<<1];
int cnt,l,r,val,la,s1[N],s2[S],m,n,ms,bl[N];;
void solve1(){
	int pl=1,pr=1,sl,sr,an=0,srr;
	for(;l>a[pl].size;pl=a[pl].r)l-=a[pl].size;
	for(;r>a[pr].size;pr=a[pr].r)r-=a[pr].size;sl=l,sr=r;
	if(pl==pr){
		for(int i=l;i<=r;i++)s1[a[pl].a[i]]++,s2[bl[a[pl].a[i]]]++;
		for(int i=0;val>s2[i];an+=ks,i++)val-=s2[i];an--;
		for(;val>0;)val-=s1[++an];printf("%d\n",la=an);
		for(int i=sl;i<=sr;i++)s1[a[pl].a[i]]--,s2[bl[a[pl].a[i]]]--;return;
	}
	for(;l<=a[pl].size;l++)s1[a[pl].a[l]]++,s2[bl[a[pl].a[l]]]++;
	for(;r;r--)s1[a[pr].a[r]]++,s2[bl[a[pr].a[r]]]++;pr=a[pr].l;
	for(int i=0;val>(srr=s2[i]+(a[pr].s2[i]-a[pl].s2[i]));an+=ks,i++)val-=srr;an--;
	for(;val>0;)val-=(s1[++an]+a[pr].s1[an]-a[pl].s1[an]);printf("%d\n",la=an);pr=a[pr].r;
	for(l=sl;l<=a[pl].size;l++)s1[a[pl].a[l]]--,s2[bl[a[pl].a[l]]]--;
	for(r=sr;r;r--)s1[a[pr].a[r]]--,s2[bl[a[pr].a[r]]]--;return;
}
void solve2(){
	int pl=1;for(;l>a[pl].size;pl=a[pl].r)l-=a[pl].size;
	int data=a[pl].a[l];a[pl].a[l]=val;
	for(;pl;pl=a[pl].r)a[pl].s1[data]--,a[pl].s1[val]++,a[pl].s2[bl[data]]--,a[pl].s2[bl[val]]++;
}
void solve3(){
	int pl=1,las;for(;l>a[pl].size&&pl;pl=a[pl].r)l-=a[pl].size,las=pl;
	if(l&&pl==0)pl=las,l=a[las].size+1;
	for(int i=a[pl].size;i>=l;i--)a[pl].a[i+1]=a[pl].a[i];a[pl].a[l]=val;
	for(int i=pl;i;i=a[i].r)a[i].s1[val]++,a[i].s2[bl[val]]++;a[pl].size++;
	if(a[pl].size>=2*ms){
		++cnt;for(int i=0;i<N;i++)a[cnt].s1[i]=a[pl].s1[i];for(int i=0;i<S;i++)a[cnt].s2[i]=a[pl].s2[i];
		a[cnt].l=pl,a[cnt].r=a[pl].r;a[a[pl].r].l=cnt;a[pl].r=cnt;a[cnt].size=a[pl].size-ms;
		for(int i=1;i<=a[cnt].size;i++)a[cnt].a[i]=a[pl].a[a[pl].size-a[cnt].size+i];a[pl].size-=a[cnt].size;
		for(int i=1;i<=a[cnt].size;i++)a[pl].s1[a[cnt].a[i]]--,a[pl].s2[bl[a[cnt].a[i]]]--;
	}
}

signed main(){
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	read(m);ms=ceil(sqrt(m));for(int i=0;i<N;i++)bl[i]=i/ks;
	for(int i=1,ss=1,now;i<=m;i++){
		read(now);cnt=ss;a[ss].a[++a[ss].size]=now;a[ss].s2[bl[now]]++;a[ss].s1[now]++;
		if(a[ss].size==ms){
			a[ss].r=ss+1;a[ss+1].l=ss;ss++;
			for(int i=0;i<N;i++)a[ss].s1[i]=a[ss-1].s1[i];
			for(int i=0;i<S;i++)a[ss].s2[i]=a[ss-1].s2[i];
		}
	}read(n);char op;
	while(n--){
		char op=getchar();while(op<'A'||op>'Z')op=getchar();
		if(op=='Q'){read(l);read(r);read(val);l^=la,r^=la,val^=la;solve1();}
		if(op=='M'){read(l);read(val);l^=la,val^=la;solve2();}
		if(op=='I'){read(l);read(val);l^=la,val^=la;solve3();}
	}return 0;
}

标签:val,la,int,++,插入,小值,区间,pl,size
来源: https://www.cnblogs.com/dai-se-can-tian/p/15897631.html