不难发现,最开始有 \(n\) 条链,并且由于每个点最多有一个桥,所以我们的交换操作实际上等价于将相邻的两条链断开,然后将它们后半部分交换。并且每个点在路径中的相对位置不变。

于是考虑维护这些链。

有一个很直观的思路就是维护点对 \((i,j)\) 表示最开始第 \(i\) 条链的第 \(j\) 个点在哪条链中,我们需要快速改变它以及它后面点的引索,所以考虑把在一条链中的点对放到一棵以 \(j\) 为键值的 FHQtreap 上并维护每个点所属的 treap 然后操作就变成了分裂之后交换子树以及查询最大值,这个很好维护,可问题是点数是 \(O(nm)\) 级别的。

所以考虑维护三元组表示最开始第 \(i\) 条链上第 \(l\) 到第 \(r\) 个点当前所在的链,不难发现最开始有 \(n\) 个三元组且一次操作最多使一个三元组分裂为 \((x,l,t)\) 与 \((x,t+1,r)\) 故三元组数量为 \(O(n + m)\) 级别。

为了快速检索每个点在那个三元组中,把 \(x\) 相同的三元组放在一个可以支持快速插入删除寻找前驱后继的平衡树中,在平衡树中储存三元组所在的节点的编号即可。

如此我们便在 \(O(n \log n)\) 的时间内解决了问题。

#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
const int maxn = 5e5+114;
__gnu_pbds::tree< pair<int, int>, __gnu_pbds::null_type, less< pair<int, int> >,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update > Index[maxn];
//(r,tot)
struct Node{
int l,r,p;
int fa;
int ls,rs;
int val;
}tr[maxn];
int root[maxn];
map<int,int> found;
int tot;
int clone(int l,int r,int p){
tr[++tot].l=l,tr[tot].r=r,tr[tot].p=p,tr[tot].val=rand();
return tot;
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(tr[x].val>tr[y].val){
tr[x].rs=merge(tr[x].rs,y);
tr[tr[x].rs].fa=x;
return x;
}
else{
tr[y].ls=merge(x,tr[y].ls);
tr[tr[y].ls].fa=y;
return y;
}
}
void split(int cur,int x,int &l,int &r){
if(cur==0){
l=r=0;
return ;
}
if(tr[cur].l>x){
r=cur;
split(tr[cur].ls,x,l,tr[cur].ls);
tr[tr[cur].ls].fa=cur;
}
else{
l=cur;
split(tr[cur].rs,x,tr[cur].rs,r);
tr[tr[cur].rs].fa=cur;
}
}
int find_root(int x){//寻找点 x 所在的根
while(tr[x].fa!=0){
x=tr[x].fa;
}
return x;
}
int Ord_split(int x,int pos){//将 (x,pos) 所在的有序段分裂为 [l,x] 与 [x+1,r]
int y = (*Index[pos].lower_bound(make_pair(x,x))).second;
int lt=tr[y].l,rt=tr[y].r,p=tr[y].p;
y=find_root(y);
if(x==rt) return y;
int pos_rt=found[y];
int tr1=0,tr2=0,tr3=0;
split(y,lt-1,tr1,tr2);
split(tr2,lt,tr2,tr3);
int New1=clone(lt,x,p),New2=clone(x+1,rt,p);
found[y]=0;
y=merge(tr1,merge(New1,merge(New2,tr3)));
tr[y].fa=0,found[y]=pos_rt,root[pos_rt]=y;
Index[pos].erase(Index[pos].lower_bound(make_pair(x,x)));
Index[pos].insert(make_pair(x,New1));
Index[pos].insert(make_pair(rt,New2));
return y;
}
int n,m,q;
void build(){
for(int i=1;i<=n;i++){
int y=clone(1,m+1,i);
tr[y].fa=0,found[y]=i,root[i]=y;
Index[i].insert(make_pair(m+1,y));
}
}
int End(int x){
if(tr[x].rs==0) return tr[x].p;
else return End(tr[x].rs);
}
int query(int x){//查询从点 x 开始最后会到那个点
return End(root[x]);
}
void opt(int a,int b){
int x=Ord_split(b,a);
int y=Ord_split(b,a+1);
x=find_root(x);
y=find_root(y);
int x_pos = found[x];
int y_pos = found[y];
int tr1=0,tr2=0,tr3=0,tr4=0;
split(x,b,tr1,tr2);
split(y,b,tr3,tr4);
found[x]=0;
found[y]=0;
x=merge(tr1,tr4);
y=merge(tr3,tr2);
tr[x].fa=0,found[x]=x_pos,root[x_pos]=x;
tr[y].fa=0,found[y]=y_pos,root[y_pos]=y;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>q;
build();
for(int i=1;i<=q;i++){
int op;
cin>>op;
if(op==1){
int a,b;
cin>>a>>b;
opt(a,b);
}
else{
int a;
cin>>a;
cout<<query(a)<<'\n';
}
}
return 0;
}

P9358 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. Xcode多进程调试:WKWebView

    由于WKWebView使用的是多线程架构,渲染模块和网络模块都各自在一个单独的进程里面,因此,如果需要设置渲染模块或者网络模块里面的断点,需要做一些特殊处理. 举个例子,假设在Xcode里面设置了渲染 ...

  2. Swift中的Tuple类型

    Swift中的Tuple类型可以包含任何值,并且这些值的类型可以互相不一样.Tuple本身比较简单,需要记得也就是访问Tuple的方式. 使用变量名访问 let http404Error = (404 ...

  3. python教程6.4-json序列化

    序列化:dumps,编码,将python类型转成json对象 反序列化:loads,解码,将json对象转成python对象 pickle 模块提供了四个功能:dumps.loads.dump.loa ...

  4. Cesium教程10-把影像和天空改成背景图片

    在使用Cesium引擎时,我们经常要使用大屏适配导致地球或者模型的黑色天空盒和大屏的样式不匹配造成场景不好看的情况,这样就可以用到我们修改Cesium的天空为纯色背景,与大屏更适配,直接上代码. &l ...

  5. angular打包优化

    打包生产环境时需要的配置如下: 在angular.json里的"configurations"里配置: "configurations": { "pr ...

  6. XML Schema 复杂元素类型详解:定义及示例解析

    在XML Schema(XSD)中,复杂元素是指包含其他元素和/或属性的XML元素.复杂元素可以分为四种类型: 空元素: 仅包含其他元素和/或属性的元素. 仅包含其他元素的元素: 不包含文本内容,只包 ...

  7. Base64 java图片工具类

    import org.springframework.util.Assert; import javax.imageio.ImageIO; import java.awt.image.Buffered ...

  8. containerd 源码分析:启动注册流程

    0. 前言 containerd 是一个行业标准的容器运行时,其强调简单性.健壮性和可移植性.本文将从 containerd 的代码结构入手,查看 containerd 的启动注册流程. 1. 启动注 ...

  9. 从源码的角度弄懂MyBatis动态代理开发原理

    MyBatis提供了一种动态代理实现SQL调用的功能,使用者只需要在映射文件中配置SQL语句与映射规则即可完成SQL调用和结果集封装.下面代码展示了动态代理调用的基本步骤: public void t ...

  10. jquery 给表格添加或删除一行

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...