洛谷 P3658 [USACO17FEB]Why Did the Cow Cross the Road III P(CDQ分治)
传送门
解题思路
对于一个数x,以在第一个排列中的位置作为关键值x,以在第二个排列中的位置作为关键值y,以值本身作为第三个关键值z。
将每个数都用一个三元组(x,y,z)表示出来。
最后答案就是满足 \(x_i<x_j,y_i>y_j,\left\vert {z_i-z_j} \right\vert <k\) 的三元组的个数。
很显然变成了CDQ分治的板子。
其中第三个条件可以用容斥转化为:
\[ans+=query(n)-query(min(a[nowr].z+k,n))+query(max(a[nowr].z-k-1,0))
\]
注意边界。
注意ans开long long。
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e5+5;
struct node{
int x,y,z;
}a[maxn],b[maxn];
int n,k,d[maxn],qaq[maxn];
long long ans;
bool cmp(node a,node b){
return a.x<b.x;
}
inline int lowbit(int x){
return x&(-x);
}
inline void update(int x,int v){
for(int i=x;i<=n;i+=lowbit(i)){
d[i]+=v;
}
}
inline int query(int x){
int res=0;
for(int i=x;i>=1;i-=lowbit(i)){
res+=d[i];
}
return res;
}
void divide(int l,int r){
if(l==r) return;
int mid=(l+r)/2;
divide(l,mid);
divide(mid+1,r);
int now=l,nowl=l,nowr=mid+1;
queue<int> q;
while(nowl<=mid||nowr<=r){
if(nowr<=r&&(nowl>mid||a[nowr].y>a[nowl].y)){
ans+=query(n)-query(min(a[nowr].z+k,n))+query(max(a[nowr].z-k-1,0));
b[now++]=a[nowr++];
}else{
update(a[nowl].z,1);
q.push(a[nowl].z);
b[now++]=a[nowl++];
}
}
for(int i=l;i<=r;i++) a[i]=b[i];
while(!q.empty()){
update(q.front(),-1);
q.pop();
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++){
int x;
cin>>x;
a[i].x=i;
a[i].z=x;
qaq[x]=i;
}
for(int i=1;i<=n;i++){
int x;
cin>>x;
a[qaq[x]].y=i;
}
divide(1,n);
cout<<ans;
return 0;
}