P3658 [USACO17FEB]Why Did the Cow Cross the Road III P

主要思路

cdq 分治。

思路

我们可以从某些不知名渠道中得知这道题是 cdq 分治,那么我们就可以来想一下三个条件了。

  • 因为那两条线一定要相交,所以我们就要让 \(p1_x<p2_x\) 并且 \(p1_y>p2_y\)\(p1_i\)\(p2_i\) 数组表示 \(i\) 在第一个数组和第二个数组中的位置。
  • \(|x-y|>k\) 这个其实就那树状数组枚举就好了。

所以这道题我们就可以化简成一个三维偏序那道题了,我们只需要现将 \(p1\)\(p2\) 从排序来处理然后再用一个树状数组来处理后面那个了,我们可以发现对于答案要分两种情况讨论因为可以 \(x\) 大或者 \(y\) 大。

代码

#include <bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(i,x,y) for(int i=x;i>=y;--i)
#define int long long
#define gh int
#define ru(x) cin>>x
using namespace std ;
const int N=2e6+10;
int tr[N],n,k,res;
struct node {
	int x,y;
	int val;
} s[N];
int lowbit(int x) {
	return x&-x;
}
int Ans(int x) {
	x=max(x,0ll);
	x=min(x,n);
	int res=0;
	while(x) {
		res+=tr[x];
		x-=lowbit(x);
	}
	return res;
}
void add(int x,int k) {
	while(x<=n) {
		tr[x]+=k;
		x+=lowbit(x);
	}
}
bool cmp(node a,node b) {
	return a.x<b.x;
}
bool cmp1(node a,node b) {
	return a.y>b.y;
}
void cdq(int l,int r) {//模板
	if(l==r) return ;
	int mid=l+r>>1;
	cdq(l,mid);
	cdq(mid+1,r);
	sort(s+l,s+1+mid,cmp1);
	sort(s+1+mid,s+1+r,cmp1);
	int j=l;
	rep(i,mid+1,r) {
		while(j<=mid&&s[j].y>s[i].y) {
			add(s[j].val,1);
			j++;
		}
		res+=Ans(s[i].val-k-1)+Ans(n)-Ans(s[i].val+k); //分两种情况讨论
	}
	rep(i,l,j-1) add(s[i].val,-1); //为了不改变清零
}
signed main() {
	ru(n),ru(k);
	rep(i,1,n) {
		gh x;
		ru(x);
		s[x].val=x;
		s[x].x=i;
	}
	rep(i,1,n) {
		gh x;
		ru(x);
		s[x].y=i;
	}
	sort(s+1,s+1+n,cmp); //先按第一维排序
	cdq(1,n);
	cout<<res<<endl;
	return false;
}

posted @ 2024-01-31 11:25  highkj  阅读(6)  评论(0)    收藏  举报