[NOIP2017D2T3]列队

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2017D2T3]列队相关的知识,希望对你有一定的参考价值。

虽然放在第三题但是其实这题没有什么思维难度,就是建$n$棵区间节点平衡树维护每行的前$m-1$个数,再建一棵平衡树维护最后一列

我用了splay,维护移动操作的确是挺简单的

但考前没有写过这种点代表区间而且要动态开点的题,怕写错不敢写,只写了60分

但实际上还是得敢写,既然自己肝了那么久splay确保自己不会写错那么为什么不试试新东西呢

其实也不是太困难,要找$x$,如果当前区间为$[l,r]$且$l\leq x\leq r$就把区间分成$[l,x-1],x,[x+1,r]$三部分就行了,没有太多细节

割分与合并记得更新父节点的信息就好

#include<stdio.h>
#define ll long long
struct node{
	ll l,r;
	int siz,fa,ch[2];
}t[1200010];
int root[300010],tot,n,m;
void pushup(int x){
	t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+(int)(t[x].r-t[x].l+1);
}
void rot(int x){
	int y,z,B,f;
	y=t[x].fa;
	z=t[y].fa;
	f=(t[y].ch[0]==x);
	B=t[x].ch[f];
	t[x].fa=z;
	t[y].fa=x;
	if(B)t[B].fa=y;
	t[x].ch[f]=y;
	t[y].ch[f^1]=B;
	if(t[z].ch[0]==y)t[z].ch[0]=x;
	if(t[z].ch[1]==y)t[z].ch[1]=x;
	pushup(y);
	pushup(x);
}
void splay(int x){
	int y,z;
	while(t[x].fa){
		y=t[x].fa;
		z=t[y].fa;
		if(z)rot((t[z].ch[0]==y&&t[y].ch[0]==x)||(t[z].ch[1]==y&&t[y].ch[1]==x)?y:x);
		rot(x);
	}
}
int getkth(int x,int k){
	if(t[t[x].ch[0]].siz<k&&k<=t[x].siz-t[t[x].ch[1]].siz){
		ll p=t[x].l+(ll)(k-t[t[x].ch[0]].siz-1);
		if(t[x].l<p){
			tot++;
			t[tot].l=t[x].l;
			t[tot].r=p-1;
			t[tot].fa=x;
			t[tot].ch[0]=t[x].ch[0];
			t[t[x].ch[0]].fa=tot;
			t[x].ch[0]=tot;
			t[x].l=p;
			pushup(tot);
		}
		if(p<t[x].r){
			tot++;
			t[tot].l=p+1;
			t[tot].r=t[x].r;
			t[tot].fa=x;
			t[tot].ch[1]=t[x].ch[1];
			t[t[x].ch[1]].fa=tot;
			t[x].ch[1]=tot;
			t[x].r=p;
			pushup(tot);
		}
		pushup(x);
		return x;
	}
	int f;
	if(k<=t[t[x].ch[0]].siz)f=getkth(t[x].ch[0],k);
	if(k>t[x].siz-t[t[x].ch[1]].siz)f=getkth(t[x].ch[1],k-t[x].siz+t[t[x].ch[1]].siz);
	pushup(x);
	return f;
}
void build(int l,int r,int&x){
	if(x==0){
		tot++;
		x=tot;
	}
	int mid=(l+r)>>1;
	t[x].l=t[x].r=m*(ll)mid;
	if(l<mid){
		build(l,mid-1,t[x].ch[0]);
		t[t[x].ch[0]].fa=x;
	}
	if(mid<r){
		build(mid+1,r,t[x].ch[1]);
		t[t[x].ch[1]].fa=x;
	}
	pushup(x);
}
int merge(int x,int y){
	if(x==0||y==0)return x|y;
	while(t[x].ch[1])x=t[x].ch[1];
	splay(x);
	t[x].ch[1]=y;
	t[y].fa=x;
	pushup(x);
	return x;
}
int split(int p){
	int k,j;
	k=t[p].ch[0];
	j=t[p].ch[1];
	t[p].ch[0]=t[p].ch[1]=0;
	t[k].fa=t[j].fa=0;
	pushup(p);
	return merge(k,j);
}
int main(){
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	int q,i,x,y,p,f;
	scanf("%d%d%d",&n,&m,&q);
	if(m>1){
		for(i=1;i<=n;i++){
			root[i]=i;
			t[i].l=m*(ll)(i-1)+1ll;
			t[i].r=m*(ll)(i-1)+(ll)(m-1);
			t[i].siz=m-1;
		}
		tot=n;
	}
	build(1,n,root[n+1]);
	while(q--){
		scanf("%d%d",&x,&y);
		if(y==m){
			p=getkth(root[n+1],x);
			splay(p);
			printf("%lld\n",t[p].l);
			root[n+1]=split(p);
			root[n+1]=merge(root[n+1],p);
		}else{
			p=getkth(root[x],y);
			splay(p);
			printf("%lld\n",t[p].l);
			f=getkth(root[n+1],x);
			splay(f);
			root[x]=split(p);
			root[n+1]=split(f);
			root[x]=merge(root[x],f);
			root[n+1]=merge(root[n+1],p);
		}
	}
}

以上是关于[NOIP2017D2T3]列队的主要内容,如果未能解决你的问题,请参考以下文章

学术篇NOIP2017 d2t3 列队phalanx splay做法

[luogu P3960] [noip2017 d2t3] 队列

[LuoguP2161[ [SHOI2009]会场预约 (splay)

NOIP2014D2T3解方程

noip2018 d2t3 保卫王国 解题报告

[Luogu 3958] NOIP2017 D2T1 奶酪