建立映射\(p[a[i]]=i\),把\(b[i]\)变成\(p[b[i]]\),然后变成在\([l_b,r_b]\)的区间里查询元素\(x\) \((l_a\le x \le r_a)\)的出现次数
等等这不就是矩形内数点的问题吗?看别人有写\(cdq\)的有写线段树+扫描线的,这些方法我都不会直接树状数组套权值线段树= =空间是个大问题所以要回收删除的点= =
代码:
#include <bits/stdc++.h>
#define N 200010
#define rd(x) scanf("%d",&x)
#define lowbit(x) (x&-x)
using namespace std;
stack<int>s;
int cnt=0,n;
int a[N*196],lson[N*196],rson[N*196],b[N],p[N];
inline int rec(){
int x=s.top();s.pop();
lson[x]=rson[x]=a[x]=0;
return x;
}
inline int newnode(){
int x;
if(!s.empty()) x=rec();
else x=++cnt;
return x;
}
void add(int l,int r,int &x,int y,int z){
if(!x) x=newnode();
a[x]+=z;
if(l<r){
int mid=l+r>>1;
if(y<=mid) add(l,mid,lson[x],y,z);
else add(mid+1,r,rson[x],y,z);
}
if(!a[lson[x]] && lson[x]){
s.push(lson[x]);
lson[x]=0;
}
if(!a[rson[x]] && rson[x]){
s.push(rson[x]);
rson[x]=0;
}
}
int query(int l,int r,int x,int L,int R){
if(!x) return 0;
if(L<=l && r<=R) return a[x];
int mid=l+r>>1,res=0;
if(L<=mid) res+=query(l,mid,lson[x],L,R);
if(R>mid) res+=query(mid+1,r,rson[x],L,R);
return res;
}
int rootb[N];
inline void ins(int x,int y,int z){
for(int i=x;i<=n;i+=lowbit(i)) add(1,n,rootb[i],y,z);
}
inline int ask(int x,int y,int a,int b){
int ans=0;
for(int i=y;i>0;i-=lowbit(i)) ans+=query(1,n,rootb[i],a,b);
for(int i=x-1;i>0;i-=lowbit(i)) ans-=query(1,n,rootb[i],a,b);
return ans;
}
int main(){
int m,i,op,la,ra,lb,rb;
rd(n),rd(m);
for(i=1;i<=n;++i) rd(la),p[la]=i;
for(i=1;i<=n;++i){
rd(b[i]);
ins(i,p[b[i]],1);
}
while(m--){
rd(op);
if(op==1){
rd(la),rd(ra),rd(lb),rd(rb);
printf("%d\n",ask(lb,rb,la,ra));
} else{
rd(la),rd(lb);
ins(la,p[b[la]],-1);
ins(lb,p[b[lb]],-1);
swap(b[la],b[lb]);
ins(la,p[b[la]],1);
ins(lb,p[b[lb]],1);
}
}
}