[BJOI2019]送别——非旋转treap
题目链接:
我们将每段墙的每一面看成一个点,将每个点与相邻的点(即按题中规则前进或后退一步能走到的点)连接。那么图中所有点就形成了若干个环,而添加一段墙或删除一段墙就是把两个环合并或者将一个环拆成两个环(当然可能只是在环上插入或删除两个点)。将每个环从任意位置拆成序列,用平衡树(平衡树需要能合并、分裂)维护即可。我们记录每个坐标点的上下左右是否有墙,如果一个坐标点的四个方向都没有墙则视为这个点是空的。
对于插入,有四种情况:
1、插入墙的两端都是空的,直接将插入墙的两个点合并为一个环即可。
2、插入墙的一端是空的,在另一端顺时针或逆时针找到遇到的第一面墙,从那里将序列分成两段,将插入墙的两个点依次插入。
3、插入墙的两端都不是空的,但两端属于不同环,两端分别顺时针找到遇到的第一面墙从那里将序列分裂然后将两个环拆成的四个序列以及插入墙的两个点按顺序合并即可。
4、插入墙的两端都不是空的,但两端属于同一个环,两端分别顺时针找到遇到的第一面墙从那里拆开然后将两个环拆成的四个序列与插入墙的两个点分别合并成两个序列。
对于删除,同样有上述四种情况,像上面说的一样讨论一下即可。
注意当将一个序列连续两次分裂时,要判断一下第二次的分裂点属于第一次分裂出来的哪个序列。
因为每次分裂或合并时无法知道操作点所属$treap$的根,属于我们将每个点的父节点记录下来然后反向分裂(即自下而上分裂)。
写的时候不要按顺时针或逆时针判断位于某个点时的方向,对于竖墙,左下右上;对于横墙,上左下右。
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int f[1200010];
int ls[1200010];
int rs[1200010];
int r[1200010];
int size[1200010];
int vis[510][510][4];
int n,m,q;
int opt;
int a,b,c,d,e;
int s,t;
int x,y,z,w;
int sum;
int root;
inline void pushup(int rt)
{
size[rt]=size[ls[rt]]+size[rs[rt]]+1;
}
inline int merge(int x,int y)
{
if(!x||!y)
{
return x+y;
}
if(r[x]<r[y])
{
rs[x]=merge(rs[x],y);
f[rs[x]]=rs[x]?x:0;
pushup(x);
return x;
}
else
{
ls[y]=merge(x,ls[y]);
f[ls[y]]=ls[y]?y:0;
pushup(y);
return y;
}
}
inline void split(int rt,int &a,int &b)
{
int x=ls[rt],y=rs[rt];
ls[rt]=rs[rt]=0;
int now=rt;
pushup(rt);
while(f[rt])
{
if(ls[f[rt]]==rt)
{
ls[f[rt]]=y;
f[y]=f[rt];
y=f[rt];
pushup(y);
}
else
{
rs[f[rt]]=x;
f[x]=f[rt];
x=f[rt];
pushup(x);
}
rt=f[rt];
}
f[x]=f[y]=0;
f[now]=0;
a=x,b=y;
}
inline int find(int rt)
{
while(f[rt])
{
rt=f[rt];
}
return rt;
}
inline int rank(int rt)
{
int res=size[ls[rt]]+1;
while(f[rt])
{
if(rs[f[rt]]==rt)
{
res+=size[ls[f[rt]]]+1;
}
rt=f[rt];
}
return res;
}
inline int get(int x,int y,int id,int num)
{
if(id==1)
{
return (x-1)*(m+1)+y+num*sum;
}
else
{
return (x-1)*m+y+(m+1)*n+num*sum;
}
}
inline int check(int x,int y,int id,int num)
{
if(id==0)
{
if(num==0)
{
for(int i=1;i<=3;i++)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
else
{
for(int i=3;i>=1;i--)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
}
else if(id==1)
{
if(num==0)
{
for(int i=2;i<=4;i++)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
else
{
for(int i=4;i>=2;i--)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
}
else if(id==2)
{
if(num==0)
{
for(int i=3;i<=5;i++)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
else
{
for(int i=5;i>=3;i--)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
}
else
{
if(num==0)
{
for(int i=0;i<=2;i++)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
else
{
for(int i=2;i>=0;i--)
{
if(vis[x][y][i%4])
{
return i%4;
}
}
}
}
return -1;
}
inline int ask(int x,int y,int id,int num)
{
if(id==0)
{
return get(x,y,2,num);
}
else if(id==1)
{
return get(x,y,1,num^1);
}
else if(id==2)
{
return get(x,y-1,2,num^1);
}
else
{
return get(x-1,y,1,num);
}
}
inline void ins(int a,int b,int c,int id)
{
if(id==1)
{
if(check(b,a,1,0)==-1&&check(c,a,3,0)==-1)
{
root=merge(get(b,a,1,0),get(b,a,1,1));
}
else if(check(b,a,1,0)==-1)
{
int num=check(c,a,3,0);
x=ask(c,a,num,0);
split(x,y,z);
root=merge(merge(y,x),merge(merge(get(c-1,a,1,1),get(c-1,a,1,0)),z));
}
else if(check(c,a,3,0)==-1)
{
int num=check(b,a,1,1);
x=ask(b,a,num,1);
split(x,y,z);
root=merge(merge(y,merge(get(b,a,1,0),get(b,a,1,1))),merge(x,z));
}
else
{
int num1=check(b,a,1,1);
int num2=check(c,a,3,0);
int rt1=ask(b,a,num1,1);
int rt2=ask(c,a,num2,0);
if(find(rt1)!=find(rt2))
{
split(rt1,x,y);
split(rt2,z,w);
int fx=merge(merge(z,rt2),merge(get(b,a,1,1),merge(rt1,y)));
int fy=merge(x,merge(get(b,a,1,0),w));
root=merge(fy,fx);
}
else
{
split(rt1,x,y);
if(find(rt2)==x)
{
split(rt2,z,w);
root=merge(merge(rt1,y),merge(merge(z,rt2),get(b,a,1,1)));
root=merge(get(b,a,1,0),w);
}
else
{
split(rt2,z,w);
root=merge(merge(rt1,z),merge(rt2,get(b,a,1,1)));
root=merge(get(b,a,1,0),merge(w,x));
}
}
}
}
else
{
if(check(a,b,0,0)==-1&&check(a,c,2,0)==-1)
{
root=merge(get(a,b,2,0),get(a,b,2,1));
}
else if(check(a,b,0,0)==-1)
{
int num=check(a,c,2,0);
x=ask(a,c,num,0);
split(x,y,z);
root=merge(merge(y,x),merge(merge(get(a,b,2,0),get(a,b,2,1)),z));
}
else if(check(a,c,2,0)==-1)
{
int num=check(a,b,0,1);
x=ask(a,b,num,1);
split(x,y,z);
root=merge(merge(y,merge(get(a,b,2,1),get(a,b,2,0))),merge(x,z));
}
else
{
int num1=check(a,b,0,1);
int num2=check(a,c,2,0);
int rt1=ask(a,b,num1,1);
int rt2=ask(a,c,num2,0);
if(find(rt1)!=find(rt2))
{
split(rt1,x,y);
split(rt2,z,w);
int fx=merge(merge(z,rt2),merge(get(a,b,2,0),merge(rt1,y)));
int fy=merge(x,merge(get(a,b,2,1),w));
root=merge(fy,fx);
}
else
{
split(rt1,x,y);
if(find(rt2)==x)
{
split(rt2,z,w);
root=merge(merge(rt1,y),merge(merge(z,rt2),get(a,b,2,0)));
root=merge(get(a,b,2,1),w);
}
else
{
split(rt2,z,w);
root=merge(merge(rt1,z),merge(rt2,get(a,b,2,0)));
root=merge(get(a,b,2,1),merge(w,x));
}
}
}
}
}
inline void del(int a,int b,int c,int id)
{
if(id==1)
{
if(check(b,a,1,0)==-1&&check(c,a,3,0)==-1)
{
split(get(b,a,1,0),x,y);
}
else if(check(b,a,1,0)==-1)
{
int rt1=get(c-1,a,1,1);
int rt2=get(c-1,a,1,0);
split(rt1,x,y);
root=merge(x,y);
split(rt2,x,y);
root=merge(x,y);
}
else if(check(c,a,3,0)==-1)
{
int rt1=get(b,a,1,0);
int rt2=get(b,a,1,1);
split(rt1,x,y);
root=merge(x,y);
split(rt2,x,y);
root=merge(x,y);
}
else
{
int rt1=get(b,a,1,0);
int rt2=get(b,a,1,1);
if(find(rt1)!=find(rt2))
{
split(rt1,x,y);
split(rt2,z,w);
root=merge(merge(x,w),merge(z,y));
}
else
{
split(rt1,x,y);
if(find(rt2)==x)
{
split(rt2,z,w);
root=merge(y,z);
}
else
{
split(rt2,z,w);
root=merge(w,x);
}
}
}
}
else
{
if(check(a,b,0,0)==-1&&check(a,c,2,0)==-1)
{
split(get(a,b,2,0),x,y);
}
else if(check(a,b,0,0)==-1)
{
int rt1=get(a,b,2,0);
int rt2=get(a,b,2,1);
split(rt1,x,y);
root=merge(x,y);
split(rt2,x,y);
root=merge(x,y);
}
else if(check(a,c,2,0)==-1)
{
int rt1=get(a,b,2,0);
int rt2=get(a,b,2,1);
split(rt1,x,y);
root=merge(x,y);
split(rt2,x,y);
root=merge(x,y);
}
else
{
int rt1=get(a,b,2,0);
int rt2=get(a,b,2,1);
if(find(rt1)!=find(rt2))
{
split(rt1,x,y);
split(rt2,z,w);
root=merge(merge(z,y),merge(x,w));
}
else
{
split(rt1,x,y);
if(find(rt2)==x)
{
split(rt2,z,w);
root=merge(y,z);
}
else
{
split(rt2,z,w);
root=merge(w,x);
}
}
}
}
}
inline int query(int s,int t)
{
root=find(s);
if(root!=find(t))
{
return -1;
}
int rs=rank(s);
int rt=rank(t);
if(rs<=rt)
{
return rt-rs;
}
else
{
return size[root]-(rs-rt);
}
}
int main()
{
srand(12378);
scanf("%d%d%d",&n,&m,&q);
sum=n*(m+1)+m*(n+1);
for(int i=1;i<=2*sum;i++)
{
size[i]=1;
r[i]=rand();
}
for(int i=1;i<=m;i++)
{
root=merge(root,get(1,i,2,1));
vis[1][i][0]=vis[1][i+1][2]=1;
}
for(int i=1;i<=n;i++)
{
root=merge(root,get(i,m+1,1,0));
vis[i][m+1][1]=vis[i+1][m+1][3]=1;
}
for(int i=m;i>=1;i--)
{
root=merge(root,get(n+1,i,2,0));
vis[n+1][i][0]=vis[n+1][i+1][2]=1;
}
for(int i=n;i>=1;i--)
{
root=merge(root,get(i,1,1,1));
vis[i][1][1]=vis[i+1][1][3]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=2;j<=m;j++)
{
scanf("%d",&x);
if(x)
{
ins(j,i,i+1,1);
vis[i][j][1]=vis[i+1][j][3]=1;
}
}
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
if(x)
{
ins(i,j,j+1,2);
vis[i][j][0]=vis[i][j+1][2]=1;
}
}
}
while(q--)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
a++,b++,c++,d++;
if(a>c)swap(a,c);
if(b>d)swap(b,d);
if(b==d)
{
ins(b,a,c,1);
vis[a][b][1]=vis[c][d][3]=1;
}
else
{
ins(a,b,d,2);
vis[a][b][0]=vis[c][d][2]=1;
}
}
else if(opt==2)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
a++,b++,c++,d++;
if(a>c)swap(a,c);
if(b>d)swap(b,d);
if(b==d)
{
vis[a][b][1]=vis[c][d][3]=0;
del(b,a,c,1);
}
else
{
vis[a][b][0]=vis[c][d][2]=0;
del(a,b,d,2);
}
}
else
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
a++,b++,c++,d++;
if(a>c)swap(a,c);
if(b>d)swap(b,d);
if(b==d)
{
s=get(a,b,1,e);
}
else
{
s=get(a,b,2,e);
}
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
a++,b++,c++,d++;
if(a>c)swap(a,c);
if(b>d)swap(b,d);
if(b==d)
{
t=get(a,b,1,e);
}
else
{
t=get(a,b,2,e);
}
printf("%d\n",query(s,t));
}
}
}
[BJOI2019]送别——非旋转treap的更多相关文章
- [bzoj3173]最长上升子序列_非旋转Treap
最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...
- 关于非旋转treap的学习
非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\) split 作用:将原 ...
- [Codeforces702F]T-Shirts——非旋转treap+贪心
题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买 ...
- BZOJ5063旅游——非旋转treap
题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: ...
- BZOJ3223文艺平衡树——非旋转treap
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...
- BZOJ3224普通平衡树——非旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
- [NOIP]2017列队——旋转treap/非旋转treap
Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m. 为了便 ...
- BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)
题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...
- BZOJ1552[Cerc2007]robotic sort&BZOJ3506[Cqoi2014]排序机械臂——非旋转treap
题目描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. 输出 输出共一行,N个用空格隔开 ...
随机推荐
- SQL Server 2017命令创建新账户(test-user),并分配数据库权限
-- 1. 创建登录账号USE [master];GOCREATE LOGIN [test-user] WITH PASSWORD = 'xysu7SZ193SNX6E{{HxubPE3}vr',DE ...
- 一篇文章彻底搞懂异步,同步,setTimeout,Promise,async
之前翻看别的大佬的博客看到了关于setTimeout,promise还有async执行顺序的文章.观看了几篇之后还是没有怎么看懂,于是自己开始分析代码,并整理了此文章,我相信通过此文章朋友们能对异步同 ...
- MySql翻页查询
分页查询在网页中随处可见,那原理是什么呢?下面简单介绍一下基于MySql数据库的limit实现方法. 首先明确为什么要使用分页查询,因为数据庞大,查询不可能全部显示在页面上,如果全部显示在页面上,也会 ...
- friend
#include <iostream> using namespace std; //friend 友元,效率的问题 //get 方法和set方法,是标准封装的结果,friend破坏了这种 ...
- 程哥带你学python-[第一章-初识Python]
Python是一种解释型.面向对象.动态数据类型的高级程序设计语言. Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年. 像Perl语言一样, Pyt ...
- java入门学习总结_03
1.键盘录入 2.分支结构 键盘录入 概述 1.键盘录入:在程序运行的过程中,可以让用户录入一些数据,存储在内存的变量中,在后续的程序运行过程中,可以使用这些数据. 2.步骤: 第一步:导包,在类声明 ...
- Ubuntu 文件和目录常用命令
目标 查看目录内容 ls 切换目录 cd 创建和删除操作 touch rm mkdir 拷贝和移动文件 cp mv 查看文件内容 cat more grep 其他 echo 重定向 > 和 &g ...
- 《浏览器工作原理与实践》 <12>栈空间和堆空间:数据是如何存储的?
对于前端开发者来说,JavaScript 的内存机制是一个不被经常提及的概念 ,因此很容易被忽视.特别是一些非计算机专业的同学,对内存机制可能没有非常清晰的认识,甚至有些同学根本就不知道 JavaSc ...
- 使用JavaScript实现录入信息生成名片
首先是布局: 一个大的盒子模型套两个小的盒子模型:左边是录入信息生成界面,右边是名片显示界面. 框架: 这里新建一个css文件,用于外部链接使用装饰 /*最外层div,主框架*/ .frame{ wi ...
- 关于HA(双机冗余接口)
HA是双机接口,即说明这款防火墙支持双机冗余并行运行模式,可以用同型号的两台机器同时接上联和下联线路,并用线路将两台机器的HA口连接起来,达到协同工作,并行运行的功能. 高可用性H.A.(High A ...