CF1093E Intersection of Permutations

\(\texttt{Description}\)

Codeforces 题目链接

洛谷题目链接

  • 给定两个 \(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]);
        }
    }
}
posted @ 2023-02-28 21:38  lzyqwq  阅读(25)  评论(0)    收藏  举报