不难发现,最开始有 \(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. 用 Certbot-auto 在 letsencrypt.org申请免费 SSL 证书实现 HTTPS

    参考帖子 https://www.cnblogs.com/lzpong/p/6433189.html https://www.cnblogs.com/756623607-zhang/p/1163850 ...

  2. gin里获取http请求过来的参数

    https://www.bilibili.com/video/av68769981/?p=2 课程代码: https://www.qfgolang.com/?special=ginkuangjia&a ...

  3. 使用自定义lua解析管理器调用lua脚本中的table

    [5] 使用自定义lua解析管理器调用table 访问数组类型的table CallLuaEntrance测试脚本中内容: //------------------------------------ ...

  4. Splashtop 免费60天 大赠送

    这两天又是双11,又是 EDG 夺冠,可谓喜事连连.热闹不断.我们也给大家准备了一份长达两个月的免费福利,快乐加倍嗷. 福利详情: 1.分享这篇文章(不要设置分组可见). 2.发送您的 Splasht ...

  5. 在身份认证后建立用户对象ICurrentUser

    app.UseAuthentication(); 这个中间件添加后,他会为HttpContext.User设置一个ClaimsPrincipal对象.里面有身份认证token里面携带的信息. 其访问方 ...

  6. 当装饰者模式遇上Read Through缓存,一场技术的浪漫邂逅

    在<经验之谈:我为什么选择了这样一个激进的缓存大Key治理方案>一文中,我提到在系统中使用的缓存是旁路缓存模式,有读者朋友问,有没有用到过其他的缓存模式,本文将结合一个我曾经工作中的案例, ...

  7. 二进制安装Kubernetes(k8s)v1.30.1

    二进制安装Kubernetes(k8s)v1.30.1 https://github.com/cby-chen/Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes(k ...

  8. FFmpeg中的关键方法及结构体(二)avformat_open_input

    1.avformat_open_input 该方法声明在libavformat/avformat.h:2093 int avformat_open_input(AVFormatContext **ps ...

  9. centos7.x开机启动流程centos6.x开机启动流程

    centos6.x开机启动流程 开机加电bios自检 MBR引导将启动权交给硬盘 硬盘 0 柱面0磁道 1扇区512字节,其中 前466字节为引导 后 64字节分区表 2字节为分区结束标志 加载gru ...

  10. Swift 排查引用循环

    ------------恢复内容开始------------ 一.最近使用RxSwift在多次信号的嵌套中,发现一个对象始终始终无法释放 开始想通过Memory Graph验证是否没有释放,一直报错, ...