CF323C Two permutations

首先声明题意:

1~n的两个排列,a,b,在线询问两个区间[ l1,r1 ],[ l2,r2 ],求这两个区间内相同数字的数目。

解法:

我们不妨以a数列为基准,a[i]表示a的第i位对应的b中的位置。

那么就是在区间[ l1,r1 ]中查询有多少个数值在[ l2,r2 ]中。

不难想到权值线段树,可持久化一下,大功告成!!!

看代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node{
    int val,l,r;
}tr[maxn*25];
int n,m,a[maxn],root[maxn],ti;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    return x*f;
}
inline int build(int l,int r){
    int t=++ti;
    if(l==r)return t;
    int mid=(l+r)>>1;
    tr[t].l=build(l,mid);
    tr[t].r=build(mid+1,r);
    return t;
}
inline int modify(int h,int l,int r,int x){
    int t=++ti;
    tr[t]=tr[h];
    tr[t].val++;
    if(l==r)return t;
    int mid=(l+r)>>1;
    if(mid>=x)tr[t].l=modify(tr[t].l,l,mid,x);
    else tr[t].r=modify(tr[t].r,mid+1,r,x);
    return t;
}
int lastans;
inline int make(int x){
    return (x+lastans-1)%n+1;
}
inline int query(int h,int l,int r,int x,int y){
    if(l>y||r<x)return 0;
    if(l>=x&&r<=y)return tr[h].val;
    int mid=(l+r)>>1;
    return query(tr[h].l,l,mid,x,y)+query(tr[h].r,mid+1,r,x,y);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)
        a[read()]=i;
    root[0]=build(1,n);
    for(int i=1;i<=n;i++)
        root[i]=modify(root[i-1],1,n,a[read()]);
    m=read();
    int a,b,c,d;
    int l1,l2,r1,r2;
    for(int i=1;i<=m;i++){
        a=read(),b=read(),c=read(),d=read();
        l1=min(make(a),make(b));
        r1=max(make(a),make(b));
        l2=min(make(c),make(d));
        r2=max(make(c),make(d));
        lastans=query(root[r2],1,n,l1,r1)-query(root[l2-1],1,n,l1,r1)+1;
        printf("%d\n",lastans-1);
    }
    return 0;
}

深深地感到自己的弱小。

posted @ 2020-03-23 22:46  syzf2222  阅读(194)  评论(0编辑  收藏  举报