题目链接:

[BJOI2019]送别

我们将每段墙的每一面看成一个点,将每个点与相邻的点(即按题中规则前进或后退一步能走到的点)连接。那么图中所有点就形成了若干个环,而添加一段墙或删除一段墙就是把两个环合并或者将一个环拆成两个环(当然可能只是在环上插入或删除两个点)。将每个环从任意位置拆成序列,用平衡树(平衡树需要能合并、分裂)维护即可。我们记录每个坐标点的上下左右是否有墙,如果一个坐标点的四个方向都没有墙则视为这个点是空的。

对于插入,有四种情况:

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的更多相关文章

  1. [bzoj3173]最长上升子序列_非旋转Treap

    最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...

  2. 关于非旋转treap的学习

    非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\) split 作用:将原 ...

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

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

  4. BZOJ5063旅游——非旋转treap

    题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: ...

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

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

  6. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  7. [NOIP]2017列队——旋转treap/非旋转treap

    Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便 ...

  8. BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)

    题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...

  9. BZOJ1552[Cerc2007]robotic sort&BZOJ3506[Cqoi2014]排序机械臂——非旋转treap

    题目描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. 输出 输出共一行,N个用空格隔开 ...

随机推荐

  1. MarkDown 语法大全查询

    目录 1. 斜体和粗体 2. 分级标题 3. 超链接 3.1. 行内式 3.2. 参考式 3.3. 自动链接 4. 锚点 5. 列表 5.1. 无序列表 5.2. 有序列表 5.3. 定义型列表 5. ...

  2. centos系统基本操作命令

    系统相关命令 查看系统版本: cat  /etc/centos-release 系统更新: yum  update 用户相关命令 增加用户: useradd  [用户名] 设置密码:password  ...

  3. 安装mysql采坑记录

    安装之前彻底卸载之前的mysql,再次安装,初始化数据库那一步失败. 再次彻底卸载mysql,把原先的安装路径的文件夹删除,文件夹路径:C:\ProgramData,再次安装,成功. 总结:重装mys ...

  4. 映射重复导致的错误:Ambiguous handler methods mapped for HTTP path

    转自:https://cloud.tencent.com/developer/article/1372150 出现了两个名称一样的映射,会报如下错误: 原因: 解决方法: 出现Ambiguous Ma ...

  5. 向量的一种特殊乘法 element wise multiplication

    向量的一种特殊乘法 element wise multiplication 物体反射颜色的计算采用这样的模型: vec3 reflectionColor = objColor * lightColor ...

  6. 目标检测 — one-stage检测(一)

    总结的很好:https://www.cnblogs.com/guoyaohua/p/8994246.html 目前主流的目标检测算法主要是基于深度学习模型,其可以分成两大类:two-stage检测算法 ...

  7. vue1 计算属性

  8. js中当call或者apply传入的第一个参数是null/undefined时,js函数内执行的上下文环境是什么?

    在js中我们都知道call/apply,还有比较少用的bind;传入的第一个参数都是改变函数当前上下文对象; call/apply区别在于传的参数不同,一个是已逗号分隔字符串,一个以数组形式.而bin ...

  9. Maven如何上传ja包到远程仓库

    本文转载自沧海一屌丝的博客 https://blog.csdn.net/qq_31924435/article/details/53745811 mvn install  会将项目生成的构件安装到本地 ...

  10. Charles破解注册

    Charles破解注册English 本页面会持续更新Charles最新版破解注册方法,建议加入收藏 Charles 4.1.2 下载Charles v4.1.2 并安装 云盘下载: Windows ...