CF1093E Intersection of Permutations
\(\texttt{Description}\)
给定两个 \(1\sim n\) 的排列 \(a,b\)。有 \(m\) 次操作:
\(\texttt{1 }l_a\texttt{ }r_a\texttt{ }l_b\texttt{ }r_b\),查询 \(|\{a_i|l_a\le i\le r_a\}\cap\{b_j|l_b\le j\le r_b\}|\)。
\(\texttt{2 }x\texttt{ }y\),交换 \(b_x,b_y\)。
\(n,m\le 2\times 10^5\)。
\(\texttt{Solution}\)
首先发现查询的限制不太好处理,又由于两个数组都是排列,可以考虑建立映射:\(p_{a_i}=i\)。
然后 \(\{a_i|l_a\le i\le r_a\}\cap\{b_j|l_b\le j\le r_b\}\) 等价于 \(\{p_{a_i}|l_a\le i\le r_a\}\cap\{p_{b_j}|l_b\le j\le r_b\}\),即 \(\{a_i|l_a\le i\le r_a\}\cap\{b_j|l_b\le j\le r_b\}\) 等价于 \(\{i|l_a\le i\le r_a\}\cap\{p_{b_j}|l_b\le j\le r_b\}\)。因为相同值的 \(p\) 值肯定相同,交集中还是这些值的贡献。
所以要求的就是 \(p_{b_{l_b}}\sim p_{b_{r_b}}\) 之间在 \(l_a\sim r_a\) 范围内有几个数。考虑使用树状数组套平衡树维护。一开始先将 \(k\) 位置插入 \(p_{b_k}\),查询的时候统计前缀个数再差分,个数可以用两端的排名之差 \(+1\) 计算。
对于交换操作,先删除原位置上的值,再插入新位置上的值。因为要避免把新插入的给误删掉(我的平衡树去重)。最后要交换 \(b_x\) 和 \(b_y\)。因为下一次交换操作是基于当前状态的。
时间复杂度为 \(\mathcal{O}((n+m)\log^2n)\),空间复杂度为 \(\mathcal{O}(n\log n)\),可以接受。优点是可以在线以及空间比树状数组套权值线段树小,缺点是常数较大。
\(\texttt{Code}\)
代码要点:
-
本蒟蒻很菜不会写平衡树,所以用的是
pb_ds库中的红黑树实现的,优点是现成、码量小且这种平衡树效率较高,缺点是难以可持久化或区间反转(貌似是这样的,因为我还没有实现过)、以及STL自带的大常数。 -
查询的时候有一些情况要舍去:
-
当前区间内所有数均 \(<l_a\)。
-
当前区间内所有数均 \(>r_a\)。
-
-
可以用指令集优化代码效率。
$1.49\text{KB}$ 较短代码
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#define N 200005
#define pbds __gnu_pbds
using namespace std;
int n,m,a[N],b[N],p[N];
pbds::tree<int,pbds::null_type,less<int>,pbds::rb_tree_tag,pbds::tree_order_statistics_node_update>bit[N];
void bit_insert(int x,int k){
for(int i=x;i<=n;i+=i&-i){
bit[i].insert(k);
}
}
void bit_erase(int x,int k){
for(int i=x;i<=n;i+=i&-i){
bit[i].erase(k);
}
}
int rbt_query(int x,int ql,int qr){
auto l=bit[x].lower_bound(ql),r=bit[x].upper_bound(qr);
if(l==bit[x].end()||r==bit[x].begin()){
return 0;
}
return bit[x].order_of_key(*--r)-bit[x].order_of_key(*l)+1;
}
int bit_query(int l,int r,int ql,int qr){
int ret=0;
for(int i=r;i;i-=i&-i){
ret+=rbt_query(i,ql,qr);
}
for(int i=l-1;i;i-=i&-i){
ret-=rbt_query(i,ql,qr);
}
return ret;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",a+i);
p[a[i]]=i;
}
for(int i=1;i<=n;++i){
scanf("%d",b+i);
bit_insert(i,p[b[i]]);
}
for(int op,la,ra,lb,rb;m--;){
scanf("%d%d%d",&op,&la,&ra);
if(op&1){
scanf("%d%d",&lb,&rb);
printf("%d\n",bit_query(lb,rb,la,ra));
}else{
bit_erase(la,p[b[la]]);
bit_erase(ra,p[b[ra]]);
bit_insert(ra,p[b[la]]);
bit_insert(la,p[b[ra]]);
swap(b[la],b[ra]);
}
}
}

浙公网安备 33010602011771号