不难发现,最开始有 \(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. ERROR: Error installing mysql2: ERROR: Failed to build gem native extension [@Ubuntu 15.04]

    参考文章: https://blog.csdn.net/a60919820/article/details/101847890 安装mysql 参考:https://www.cnblogs.com/h ...

  2. docker-compose搭建的Mysql主从复制

    设置前注意下面几点: 1)要保证同步服务期间之间的网络联通.即能相互ping通,能使用对方授权信息连接到对方数据库(防火墙开放3306端口). 2)关闭selinux. 3)同步前,双方数据库中需要同 ...

  3. leaflet常用插件汇总介绍

    1.Leaflet Ant Path(线条流动效果) 在交通项目.管网应用的项目中,常常需要标注出道路的走向.河流的流向或者管线的流向等等,Leaflet Ant Path能够很好的解决这类问题: g ...

  4. C#TMS系统学习(BaseCity页面)

    C#TMS系统代码-基础页面BaseCity学习 本人纯新手,刚进公司跟领导报道,我说我是java全栈,他问我会不会C#,我说大学学过,他说这个TMS系统就给你来管了.外包已经把代码给我了,这几天先把 ...

  5. MindSponge分子动力学模拟——自定义控制器(2024.05)

    技术背景 分子动力学模拟中的控制器(Controller)可以被用于修改模拟过程中的原子坐标和原子速度等参量,从而达到控制系统特定参量的目的.例如控温器可以用于实现NVT系综,控压器可用于实现NPT系 ...

  6. 使用systemctl管理服务(nginx)

    首先调整好路径信息,修改配置文件vim /usr/lib/systemd/system/nginx.service [Unit]Description=The nginx HTTP and rever ...

  7. docker镜像仓库管理Harbor

    一 部署Harbor 前提: Harbor需要运行在docker上面,所以首先需要在harbor部署机器上面自行部署docker和docker-compose docker-compose安装命令如下 ...

  8. 为什么我们要用Spring Boot

    最近我面试了不少人,其中不乏说对 Spring Boot 非常熟悉的,然后当我问到一些 Spring Boot 核心功能和原理的时候,没人能说得上来,或者说不到点上,可以说一个问题就问趴下了! 这是我 ...

  9. OceaBase 分区表创建技巧

    最近遇在干个核心的金融项目,规模很大,客户主要是用oracle数据库,现在需要适配ob,原来在oracle就是分区表的迁来ob以后需要进行改造. oracle默认使用是堆表(ht),而ob使用的是索引 ...

  10. kubernetes pod升级与回滚扩容与缩容

    运行一个容器: apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revisio ...