• 洛谷P3960 列队(NOIP2017)(Splay)


    洛谷题目传送门

    最弱的Splay。。。。。。

    暴力模拟30分(NOIP2017实际得分,因为那时连Splay都不会)。。。。。。

    发现只是一个点从序列里搬到了另一个位置,其它点的相对位置都没变,可以想到维护每一行的前(m-1)列的平衡树,还有最后一列的平衡树。但是如果对所有点都开一个Splay,因为MLE的问题,只能获得60分。。。。。。

    因为询问次数只有(O(N))级别,可以发现操作完之后还有很多行的某一些区间是连续的区间。考虑每个点对应一段区间,当某操作使得一个连续区间被破坏掉的时候,动态开点,把区间拆成至多(3)段(其中中间一段就是一个点),再把中间那个点移走。

    时间复杂度(O(qlog n)),空间复杂度(O(4n+2q))(因为需要哨兵节点的空间)。由于常数巨大,最后两个点不开氧气根本进不了1000ms。。。。。。insert常数大,所以下面用了一种暴力插入的办法——强行把新点塞到根与左/右儿子之间

    实现细节巨多,Debug 1day。。。。。。

    #include<cstdio>
    #include<cstdlib>
    typedef long long LL;
    #define RG register
    #define R RG int
    #define II inline int
    #define IV inline void
    #define G ch=getchar()
    #define lc c[x][0]
    #define rc c[x][1]
    const int N=300009,M=N*6;//空间开够
    int f[M],c[M][2],v[M],s[M],end[N];
    //end是每个平衡树的末哨兵,为了方便,每次操作完都把它旋到根
    LL id[M];
    IV in(R&z){
    	RG char G;
    	while(ch<'-')G;
    	z=ch&15;G;
    	while(ch>'-')z*=10,z+=ch&15,G;
    }
    IV pushup(R x){
    	s[x]=s[lc]+s[rc]+v[x];
    }
    IV rotate(R x){
    	R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
    	c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
    	pushup(f[w]=y);f[y]=x;f[x]=z;
    }
    IV splay(R x,R tg){
    	R y;
    	while(tg!=(y=f[x])){
    		if(tg!=f[y])
    			rotate((c[f[y]][0]==y)^(c[y][0]==x)?x:y);
    		rotate(x);
    	}
    	pushup(x);
    }
    II find(R x,R k){
    	while(1){
    		if(k<=s[lc])x=lc;
    		else if((k-=s[lc])<=v[x])break;
    		else k-=v[x],x=rc;
    	}
    	splay(x,0);
    	return x;
    }
    II findr(R x){//找前驱
    	while(rc)x=rc;
    	return x;
    }
    II findl(R x){//找后继
    	while(lc)x=lc;
    	return x;
    }
    #define np(I,V,S) id[++p]=I;v[p]=V;s[p]=S//动态开点
    #define del(P)
    	splay(rt=findr(lc),0);
    	splay(x=findl(rc),rt);
    	P=lc;lc=0;pushup(x);pushup(rt)//暂时删除并把下标存在变量P中
    #define con(P,C) f[c[P][0]=C]=P//建立父子关系
    #define ins(P) con(P,lc);con(x,P)//强行插入
    #define add(P) ins(P);pushup(P);pushup(x)//插入并更新
    int main(){
    	R p=0,n,m,q,i,a,b,x,y,z,rt;
    	in(n);in(m);in(q);
    	for(i=1;i<=n;++i){
    		np(0,1,1);              con(p+1,p);
    		np((LL)(i-1)*m+1,m-1,m);con(p+1,p);
    		np(0,1,m+1);            end[i]=p;
    	}//初始都是暴力建树,直接弄一条链
    	for(i=0;i<=n;++i){
    		np((LL)i*m,1,i+1);      con(p+1,p);
    	}
    	np(0,1,i+1);                end[0]=p;
    	while(q--){
    		in(a);in(b);
    		if(b==m){//特判
    			x=find(end[0],a+1);
    			printf("%lld
    ",id[x]);
    			del(y);splay(x=end[0],0);add(y);
    			continue;
    		}
    		x=find(end[a],b+1);
    		if(v[x]>1){
    			y=s[lc];//仔细判断是否需要开点
    			if(y<b){
    				np(id[x],b-y,b);ins(p);
    			}
    			if(y+v[x]-1>b){
    				np(id[x]-y+b+1,v[x]+y-b-1,v[p]+s[rc]);
    				f[c[p][1]=rc]=p;f[rc=p]=x;
    			}
    			id[x]+=b-y;v[x]=1;
    		}
    		printf("%lld
    ",id[x]);del(y);
    		x=find(end[0],a+1);del(z);
    		splay(x=end[a],0);add(z);//在Splay中互换位置
    		splay(x=end[0],0);add(y);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Linux内核同步
    Linux内核同步
    Linux内核同步
    Linux内核同步
    Linux内核同步
    Linux中断
    Linux中断
    Linux中断
    Linux中断
    Linux中断
  • 原文地址:https://www.cnblogs.com/flashhu/p/8690103.html
Copyright © 2020-2023  润新知