luogu P3658 [USACO17FEB]Why Did the Cow Cross the Road III P
题面传送门
把交叉转化成\(x_i>x_j\&\&y_i>y_j\)
然后就是三维偏序板子题了。注意树套树过不去,要用\(cdq\)分治。
树状数组随便维护一下就好了。
代码实现:
#include<cstdio>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,k,x,y,z,a[100039],b[100039],f[100039];
long long ans;
struct yyy{int x,y,z;}s[100039];
inline bool cmp1(yyy x,yyy y){return x.x<y.x;}
inline bool cmp2(yyy x,yyy y){return x.y<y.y;}
inline void get(int x,int y){while(x<=n) f[x]+=y,x+=x&-x;}
inline int find(int x){int ans=0;while(x) ans+=f[x],x-=x&-x;return ans;}
inline void slove(int x,int y){
if(x==y) return;
int m=x+y>>1,l=m,i;
slove(x,m);slove(m+1,y);
sort(s+x,s+m+1,cmp2);sort(s+m+1,s+y+1,cmp2);//printf("%d %d\n",x,y);
for(i=y;i>=m+1;i--){
while(l>=x&&s[l].y>=s[i].y) get(s[l--].z,1);
ans=ans+find(n)-find(min(s[i].z+k,n))+find(max(s[i].z-k-1,0));
printf("%lld\n",ans);
}
for(i=l+1;i<=m;i++) get(s[i].z,-1);
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
register int i;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)scanf("%d",&a[i]),s[a[i]].z=a[i],s[a[i]].x=i;
for(i=1;i<=n;i++) scanf("%d",&a[i]),s[a[i]].y=i;
sort(s+1,s+n+1,cmp1);slove(1,n);
printf("%lld\n",ans);
}