首先声明题意:
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 ",lastans-1); } return 0; }
深深地感到自己的弱小。