CF1093:E. Intersection of Permutations(树状数组套主席树)

Posted hua-dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1093:E. Intersection of Permutations(树状数组套主席树)相关的知识,希望对你有一定的参考价值。

题意:给定长度为N的a数组,和b数组,a和b都是1到N的排列; 有两种操作,一种是询问[L1,R1],[L2,R2];即问a数组的[L1,R1]区间和b数组的[L2,R2]区间出现了多少个相同的数字。 一种是修改b数组两个位置的值。

思路:如果把b数组每个数取对应a数组对应数的位置,即按照b的下标建立横坐标,纵坐标是它在a中的位置,那么问题就成了,询问在区间[L2,R2]里面,多少个数在[L1,R1]这区间。  这很明显就是主席树可以解决的了。时间复杂度是O(N*logN*logN);常数差不多是4。

因为空间的问题,但是赛场上不少树套树都MLE或者RE了。 

这里学到了回收空间:因为这里的节点不可能出现负数,所以如果一个节点的sum为0,那么子树节点的sum值都为0,那么这个子树都可以回收,即把它们赋值为0;

(cdq先补了G再回来补。分块懒得补了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
struct in{
    int l,r,sum;
    in(){l=r=sum=0;}
}s[maxn*130];
queue<int>q;
int rt[maxn],pos[maxn],a[maxn],b[maxn],N,cnt;
void add(int &Now,int L,int R,int pos,int v)
{
    if(!Now){
        if(!q.empty()) Now=q.front(),q.pop();
        else Now=++cnt;
    }
    s[Now].sum+=v;
    if(L==R) return ;int Mid=(L+R)>>1;
    if(pos<=Mid) add(s[Now].l,L,Mid,pos,v);
    else add(s[Now].r,Mid+1,R,pos,v);
    if(!s[Now].sum) {q.push(Now); Now=0;}
}
void Add(int x,int pos,int v)
{
    while(x<=N){
        add(rt[x],0,N,pos,v);
        x+=(-x)&x;
    }
}
int query(int Now,int L,int R,int l,int r)
{
    if(L>R) return 0;
    if(L<0||l<0) return 0;
    if(!Now) return 0;
    if(l<=L&&r>=R) return s[Now].sum;
    int Mid=(L+R)>>1,res=0;
    if(l<=Mid) res+=query(s[Now].l,L,Mid,l,r);
    if(r>Mid) res+=query(s[Now].r,Mid+1,R,l,r);
    return res;
}
int Query(int x,int L,int R)
{
    if(L>R) return 0; if(x<=0) return 0;
    int res=0; while(x){
        res+=query(rt[x],0,N,L,R);
        x-=(-x)&x;
    } return res;
}
int main()
{
    int M,opt,L1,R1,L2,R2,x,y;
    scanf("%d%d",&N,&M);
    rep(i,1,N) scanf("%d",&a[i]),pos[a[i]]=i;
    rep(i,1,N) scanf("%d",&b[i]);
    rep(i,1,N) Add(i,pos[b[i]],1);
    while(M--){
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d%d%d",&L1,&R1,&L2,&R2);
            int ans=Query(R2,L1,R1)-Query(L2-1,L1,R1);
            printf("%d
",ans);
        }
        else {
            scanf("%d%d",&x,&y);
            Add(x,pos[b[x]],-1); Add(y,pos[b[y]],-1);
            swap(b[x],b[y]);
            Add(x,pos[b[x]],1); Add(y,pos[b[y]],1);
        }
    }
    return 0;
}

 

以上是关于CF1093:E. Intersection of Permutations(树状数组套主席树)的主要内容,如果未能解决你的问题,请参考以下文章

CF1093E [Intersection of Permutations]

[树状数组][权值线段树] Codeforces 1093E Intersection of Permutations

Cideforces 1093E Intersection of Permutations (CDQ分治+树状数组)

CF-1093 (2019/02/10)

CF1093D Beautiful Graph

CF1093G Multidimensional Queries