zoukankan      html  css  js  c++  java
  • [NOIP2017]列队 离线+SBT

     [NOIP2017]列队

    题目描述

    Sylvia 是一个热爱学习的女♂孩子。

    前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。

    Sylvia 所在的方阵中有n×m名学生,方阵的行数为 n,列数为 m。

    为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n×m 编上了号码(参见后面的样例)。即:初始时,第 i 行第 j 列 的学生的编号是(i1)×m+j。

    然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 q件这样的离队事件。每一次离队事件可以用数对(x,y)(1xn,1ym)描述,表示第 x 行第 y 列的学生离队。

    在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:

    1. 向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 x 行第 m 列。

    2. 向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 n 行第 m 列。

    教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 n 行 第 m 列一个空位,这时这个学生会自然地填补到这个位置。

    因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。

    注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。

    输入输出格式

    输入格式:

    输入共 q+1 行。

    第 1 行包含 3 个用空格分隔的正整数 n,m,q,表示方阵大小是 n 行 m 列,一共发 生了 q 次事件。

    接下来 q 行按照事件发生顺序描述了 q 件事件。每一行是两个整数 x,y,用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 x 行第 y 列。

    输出格式:

    按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。

    输入输出样例

    输入样例#1:
    2 2 3 
    1 1 
    2 2 
    1 2 
    输出样例#1:
    1
    1
    4
    

    说明

    【输入输出样例 1 说明】

    列队的过程如上图所示,每一行描述了一个事件。 在第一个事件中,编号为 1 的同学离队,这时空位在第一行第一列。接着所有同学 向左标齐,这时编号为 2 的同学向左移动一步,空位移动到第一行第二列。然后所有同 学向上标齐,这时编号为 4 的同学向上一步,这时空位移动到第二行第二列。最后编号 为 1 的同学返回填补到空位中。

    【数据规模与约定】

    数据保证每一个事件满足 1xn,1ym

    题解:由于操作是可逆的,所以我们将所有操作反过来做,将人的移动改成询问的反向移动,那么我们只需要维护这些询问点的移动即可,不难想到用数据结构(谁告诉我NOIP考前千万别做数据结构的~)

    我们将操作顺序反过来,那么一次操作(x,y)可以看成:
    1.(n,m)的学生出队
    2.第n列中,第x行及以下的所有学生下移一格
    3.第x行中,第y列及右面的所有学生右移一格
    4.将当前询问的学生放到(x,y)处

    鉴于这些操作,我最终选择了SBT(平衡树),那么1操作就是单点删除,2,3操作就是区间加法,4操作就是单点加入。我们对每一行,以及最后一列都开一棵SBT,维护其中的所有询问即可。

    并且注意:每一行y的范围是[1,m),即如果一行的最右面的元素位于最后一列,我们要将其从这一行删除,并加入到最后一列中。

    还有一点,如果在操作1时(n,m)处有询问,说明那个询问与当前询问是重合的,所以我们记录一个类似于pre的东西,将那个询问的pre指向当前询问,并将那个询问删除。输出答案的时候直接令该询问的答案等于其pre的答案即可。

    正解是树状数组?不管了考场上想不到,写个大数据结构得了,倒是调了将近1个半点。

    最后的最后。。。注意答案是爆int的!!!(没错我就是这么滚粗的~)

    P.S:考完发现懵逼了,好像不离线也行。。。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=300010;
    typedef long long ll;
    struct node
    {
    	int ch[2],siz,val,org,tag;
    }s[maxn<<1];
    int n,m,q,tot;
    int rx,ry[maxn];
    //px指最右面那列,py指每一行
    int bel[maxn],x[maxn],y[maxn];
    ll ans[maxn];
    inline int rd()
    {
    	int ret=0;	char gc=getchar();
    	while(gc<'0'||gc>'9')	gc=getchar();
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret;
    }
    inline void pushdown(int x)
    {
    	if(s[x].tag)
    	{
    		if(s[x].ch[0])	s[s[x].ch[0]].val+=s[x].tag,s[s[x].ch[0]].tag+=s[x].tag;
    		if(s[x].ch[1])	s[s[x].ch[1]].val+=s[x].tag,s[s[x].ch[1]].tag+=s[x].tag;
    		s[x].tag=0;
    	}
    }
    inline void pushup(int x)
    {
    	s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+1;
    }
    inline void rotate(int &x,int d)
    {
    	int y=s[x].ch[d];
    	pushdown(x),pushdown(y);
    	s[x].ch[d]=s[y].ch[d^1],s[y].ch[d^1]=x;
    	pushup(x),pushup(y);
    	x=y;
    }
    inline void maintain(int &x,int d)
    {
    	if(s[s[s[x].ch[d]].ch[d]].siz>s[s[x].ch[d^1]].siz)	rotate(x,d);
    	else	if(s[s[s[x].ch[d]].ch[d^1]].siz>s[s[x].ch[d^1]].siz)	rotate(s[x].ch[d],d^1),rotate(x,d);
    	else	return ;
    	maintain(s[x].ch[d],d),maintain(s[x].ch[d^1],d^1);
    	maintain(x,d),maintain(x,d^1);
    }
    void insert(int &x,int y,int z)
    {
    	if(!x)
    	{
    		x=++tot,s[x].siz=1,s[x].ch[0]=s[x].ch[1]=s[x].tag=0,s[x].val=y,s[x].org=z;
    		return ;
    	}
    	pushdown(x);
    	int d=(y>s[x].val);
    	insert(s[x].ch[d],y,z),pushup(x);
    	maintain(x,d);
    }
    void del(int &x,int y)
    {
    	s[x].siz--,pushdown(x);
    	if(s[y].val>s[x].val)	del(s[x].ch[1],y);
    	else if(s[y].val<s[x].val)	del(s[x].ch[0],y);
    	else
    	{
    		if(!s[x].ch[0]||!s[x].ch[1])
    		{
    			x=s[x].ch[0]^s[x].ch[1];
    			return ;
    		}
    		int u=s[x].ch[1];	pushdown(u);
    		while(s[u].ch[0])	u=s[u].ch[0],pushdown(u);
    		s[x].org=s[u].org,s[x].val=s[u].val;
    		del(s[x].ch[1],u);
    	}
    }
    void updata(int x,int y)
    {
    	if(!x)	return ;
    	pushdown(x);
    	if(s[x].val>=y)
    	{
    		s[x].val++;
    		if(s[x].ch[1])	s[s[x].ch[1]].val++,s[s[x].ch[1]].tag++;
    		updata(s[x].ch[0],y);
    	}
    	else	updata(s[x].ch[1],y);
    }
    inline int findmax(int x)
    {
    	pushdown(x);
    	while(s[x].ch[1])	x=s[x].ch[1],pushdown(x);
    	return x;
    }
    inline ll point(int a,int b) {return ll(a-1)*m+b;}
    void dfs(int x,int t)
    {
    	if(!x)	return ;
    	pushdown(x);
    	if(!t)	ans[s[x].org]=point(s[x].val,m);
    	else	ans[s[x].org]=point(t,s[x].val);
    	dfs(s[x].ch[0],t),dfs(s[x].ch[1],t);
    }
    int find(int x,int y)
    {
    	if(!x)	return 0;
    	pushdown(x);
    	if(y>s[x].val)	return find(s[x].ch[1],y);
    	if(y<s[x].val)	return find(s[x].ch[0],y);
    	return x;
    }
    int main()
    {
    	//freopen("phalanx.in","r",stdin);
    	//freopen("phalanx.out","w",stdout);
    	n=rd(),m=rd(),q=rd();
    	int i;
    	for(i=1;i<=q;i++)
    	{
    		bel[i]=i;
    		x[i]=rd(),y[i]=rd();
    	}
    	for(i=q;i>=1;i--)
    	{
    		int t=findmax(rx);
    		if(s[t].val==n)
    		{
    			bel[s[t].org]=i,del(rx,t);
    		}
    		updata(rx,x[i]);
    		updata(ry[x[i]],y[i]);
    		t=findmax(ry[x[i]]);
    		if(s[t].val==m)
    		{
    			del(ry[x[i]],t),insert(rx,x[i],s[t].org);
    		}
    		if(y[i]<m)	insert(ry[x[i]],y[i],i);
    		else	insert(rx,x[i],i);
    	}
    	dfs(rx,0);
    	for(i=1;i<=n;i++)	dfs(ry[i],i);
    	for(i=1;i<=q;i++)	printf("%lld
    ",ans[i]=ans[bel[i]]);
    	return 0;
    }
  • 相关阅读:
    【2019/7/15】暑假自学——周进度报告
    用户体验评价
    《程序员修炼之道》读后感03
    《程序员修炼之道》读后感02
    《程序员修炼之道》读后感01
    《梦断代码》读后感03——为什么我们不能像造桥一样造软件
    《梦断代码》读后感02——问题的开始
    《梦断代码》读后感01——Chandle的开始
    第二阶段冲刺9
    十五周总结
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7825813.html
Copyright © 2011-2022 走看看