Sylvia 是一个热爱学习的女孩子。 
  前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。 Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m。 
  为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中的学生从 1 到 n × m 编上了号码(参见后面的样例)。即:初始时,第 i 行第 j 列的学生的编号是(i − 1) × m + j。 
  然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天中,一共发生了 q 件这样的离队事件。每一次离队事件可以用数对(x, y) (1≤x≤n, 1≤y≤m)描述,表示第 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 列。

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

样例输入

2 2 3 1 1 2 2 1 2

样例输出

1 1 4

【样例解释】

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

【数据规模】

数据保证每一个事件满足 1≤x≤n,1≤y≤m。

这道题有许多做法,树状数组、线段树、平衡树都能做。这里只讲一下平衡树treap的做法。

通过题意我们会发现每次操作只改变第x行和最后一列。所以我们可以建n+1个平衡树(每行前m-1个数是一个,最后一列是一个),这样就可以快速查找并删除要操作的点并在最后一列插入删除的点。时间复杂度是O(Q*logN)级别,但看一下数据范围n*m的矩阵9*1010(比全世界人口都要多qwq),显然是存不下的。但只有3*105次查询,所以有许多点是不会被改动的,那么我们可以把这些点缩成一个点,然后记录一下每个点的左端和长度。每次操作时把操作的数所在点分成三个点(l~x-1;x;x+1~r)。所以最多只有2*q+2*n个点。每个平衡树在初始时只有一个点(最后一列的那个树是n个点)。注意非旋转treap分裂时并不是像常规一样分裂成两棵树,而是分裂成两个数和查询点三部分。

旋转treap

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a,b;
int tot;
int n,m,q;
long long ans;
int w[3000010];
int ls[3000010];
int rs[3000010];
int root[300010];
int size[3000010];
long long l[3000010];
long long r[3000010];
void updata(int x)
{size[x]=size[ls[x]]+size[rs[x]]+r[x]-l[x]+1;
}
void lturn(int &x)
{if(!rs[x]){return ;}int t=rs[x];rs[x]=ls[t];ls[t]=x;size[t]=size[x];updata(x);x=t;
}
void rturn(int &x)
{if(!ls[x]){return ;}int t=ls[x];ls[x]=rs[t];rs[t]=x;size[t]=size[x];updata(x);x=t;
}
void rotate(int &x)
{if(w[rs[x]]<w[x]){lturn(x);}if(w[ls[x]]<w[x]){rturn(x);}
}
void insert(int &x,long long L,long long R)
{if(!x){x=++tot;l[x]=L;r[x]=R;w[x]=rand();updata(x);return ;}    insert(rs[x],L,R);updata(x);rotate(x);
}
void del(int &x,int num)
{if(!x){return ;}if(x==num){if(ls[x]*rs[x]==0){x=ls[x]+rs[x];}else if(w[ls[x]]<w[rs[x]]){rturn(x);}    else if(w[ls[x]]>=w[rs[x]]){lturn(x);}del(x,num);return ;}if(ls[x]==num){del(ls[x],num);    }if(rs[x]==num){del(rs[x],num);}updata(x);
}
void find1(int &x,int v)
{if(!x)    {return ;}if(size[ls[x]]>=v){find1(ls[x],v);updata(x);rotate(x);return ;}else if(size[x]-size[rs[x]]<v){find1(rs[x],v-size[x]+size[rs[x]]);updata(x);rotate(x);    return ;}v-=size[ls[x]];ans=l[x]+v-1;if(v==1&&v==size[x]-size[rs[x]]-size[ls[x]]){del(x,x);return ;}if(v==1){l[x]++;updata(x);}else if(v==size[x]-size[ls[x]]-size[rs[x]]){r[x]--;updata(x);    }else {int sum=++tot;r[sum]=r[x];r[x]=l[x]+v-2;l[sum]=l[x]+v;rs[sum]=rs[x];rs[x]=sum;updata(sum);updata(x);w[sum]=rand();rotate(x);    }
}
void find2(int &x,int v)
{if(!x){return ;}if(size[ls[x]]>=v){find2(ls[x],v);updata(x);rotate(x);return ;}else if(size[x]-size[rs[x]]<v){find2(rs[x],v-size[x]+size[rs[x]]);updata(x);rotate(x);return ;}ans=l[x];del(x,x);
}
int main()
{srand(37975);scanf("%d%d%d",&n,&m,&q);for(long long i=1;i<=n;i++){insert(root[i],(i-1)*m+1,(i-1)*m+m-1);}for(long long i=1;i<=n;i++){insert(root[n+1],i*m,i*m);}while(q--){scanf("%d%d",&a,&b);if(b<m){find1(root[a],b);    }else{find2(root[n+1],a);}long long s=ans;printf("%lld\n",s);if(b<m){find2(root[n+1],a);long long t=ans;insert(root[a],t,t);}insert(root[n+1],s,s);}return 0;
}

非旋转treap

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define pr pair<int,ll>
using namespace std;
int rs[2000010];
int ls[2000010];
ll l[2000010];
ll r[2000010];
int size[2000010];
int num[2000010];
int root[500010];
int v[2000010];
int n,m,q;
int x,y;
int cnt;
int a,b,c,d;
pr now;
int build(ll L,ll R)
{int rt=++cnt;size[rt]=num[rt]=(int)(R-L+1);l[rt]=L;r[rt]=R;v[rt]=rand();return rt;
}
void pushup(int rt)
{size[rt]=size[ls[rt]]+size[rs[rt]]+num[rt];
}
pr split(int rt,int k,int &x,int &y)
{if(size[ls[rt]]>=k){y=rt;pr res=split(ls[rt],k,x,ls[y]);pushup(rt);return res;}else if(size[ls[rt]]+num[rt]>=k){x=ls[rt];y=rs[rt];return make_pair(rt,1ll*(k-size[ls[rt]]+l[rt]-1));}else{x=rt;pr res=split(rs[rt],k-size[ls[rt]]-num[rt],rs[x],y);pushup(rt);return res;}
}
int merge(int x,int y)
{if(!x||!y){return x+y;}if(v[x]<v[y]){rs[x]=merge(rs[x],y);pushup(x);return x;}else{ls[y]=merge(x,ls[y]);pushup(y);return y;}
}
int main()
{srand(12378);scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++){root[i]=build(1ll*(i-1)*m+1,1ll*i*m-1);}root[n+1]=build(1ll*m,1ll*m);for(int i=2;i<=n;i++){root[n+1]=merge(root[n+1],build(1ll*i*m,1ll*i*m));}while(q--){scanf("%d%d",&x,&y);if(y==m){now=split(root[n+1],x,a,b);ls[now.first]=rs[now.first]=0;size[now.first]=num[now.first];printf("%lld\n",now.second);root[n+1]=merge(a,merge(b,now.first));}else{now=split(root[x],y,a,b);printf("%lld\n",now.second);if(l[now.first]!=now.second){cnt++;l[cnt]=l[now.first];r[cnt]=now.second-1;size[cnt]=num[cnt]=(int)(r[cnt]-l[cnt]+1);v[cnt]=rand();a=merge(a,cnt);}if(r[now.first]!=now.second){cnt++;l[cnt]=now.second+1;r[cnt]=r[now.first];size[cnt]=num[cnt]=(int)(r[cnt]-l[cnt]+1);v[cnt]=rand();b=merge(cnt,b);}root[x]=merge(a,b);l[now.first]=now.second;r[now.first]=now.second;num[now.first]=size[now.first]=1;ls[now.first]=rs[now.first]=0;root[n+1]=merge(root[n+1],now.first);now=split(root[n+1],x,c,d);ls[now.first]=rs[now.first]=0;size[now.first]=num[now.first];root[n+1]=merge(c,d);root[x]=merge(root[x],now.first);}}
}

转载于:https://www.cnblogs.com/Khada-Jhin/p/8862314.html

[NOIP]2017列队——旋转treap/非旋转treap相关推荐

  1. BZOJ4864[BeiJing 2017 Wc]神秘物质——非旋转treap

    题目描述 21ZZ 年,冬. 小诚退休以后, 不知为何重新燃起了对物理学的兴趣. 他从研究所借了些实验仪器,整天研究各种微观粒子.这 一天, 小诚刚从研究所得到了一块奇异的陨石样本, 便迫不及待地开始 ...

  2. 4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap

    国际惯例的题面: 这种维护排序序列,严格大于的进行操作的题都很套路...... 我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好. 显然第一个区间的不会变化,第二个区间的会被平移进第 ...

  3. [Codeforces702F]T-Shirts——非旋转treap+贪心

    题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买 ...

  4. BZOJ3223文艺平衡树——非旋转treap

    此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...

  5. BZOJ1251序列终结者——非旋转treap

    题目描述 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技 ...

  6. luoguP5055 【模板】可持久化文艺平衡树 可持久化非旋转treap

    luoguP5055 [模板]可持久化文艺平衡树 可持久化非旋转treap 好题. Code: #include<bits/stdc++.h> using namespace std; # ...

  7. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。(js代码)

    1.题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的 ...

  8. 剑指offer:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。

    剑指offer算法题 二分查找,旋转数组最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组[3, ...

  9. 6:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转

    public class Solution {public int minNumberInRotateArray(int [] array) {int min=array[0];for(int i=1 ...

最新文章

  1. pt,px,rem和em之间区别总结
  2. 纯JS制作的窗户雨滴效果
  3. 中国致密气行业十四五前景分析及发展规划远景报告2022年版
  4. 测试TensorFlow Object Detection API
  5. 《剑指offer》用两个栈实现队列
  6. 数学--数论-- AtCoder Beginner Contest 151(组合数+数学推导)好题(๑•̀ㅂ•́)و✧
  7. Graph Valid Tree
  8. 【linux】Linux cp命令拷贝 不覆盖原有的文件
  9. python意外退出_有趣的Python上下文管理器
  10. 模块化配电系统在高密度数据中心的应用
  11. 项目管理的10个经典故事
  12. MIMO检测之ZF,MMSE,ML算法matlab代码
  13. (Mix) The task phx.new could not be found
  14. 盲子强巴(连载)二、
  15. Facebook MySQL工程师吐槽MemSQL:MySQL比你们快无数倍
  16. 傅盛:最可怕的不是把事情做差,而是越做越好后被淘汰
  17. .NET DataGridView 单元格添加日历选择控件
  18. 如何看linux是arm还是amd_享受还是想瘦?看游泳如何让你“享瘦”
  19. 2004年国内十大暴利行业
  20. 最全与最好的——CUDA入门教程

热门文章

  1. 关于php正则表达式得选择题,经典PHP笔试题
  2. c语言中缀表达式求值_数据结构-第三章:栈和队列(栈的应用、括号匹配、表达式转换)
  3. vscode 国内镜像快速下载
  4. 20190803:栈实践(最小栈)
  5. dos创建mysql数据库_用命令创建MySQL数据库
  6. ios弧形进度条_iOS手把手教你实现圆形进度条
  7. 在java编程中会使用汉字字符_在java程序中将中文字符写入文件中或者是将文件中的中文字符读入程序时会出现乱码或者一串“?”,求...
  8. 每日总结app_焊工日常工作的主要职责是什么?焊工证考试用什么APP复习?
  9. eclipse中编译运行maven项目使用jetty
  10. ‘adb‘ 不是内部或外部命令and Error while executing: am start -n解决