- HYSBZ - 4991
-
题意: 第一列 1-n的排列 ,第二列 1-n的排列。 相同数字连边 ,问 有多少组 数字 是有交点的并且 绝对值之差>K
思路:处理一下 1-n 在第一列的位置,1-n在第二列的位置。按照第一列的位置从小到大排序,然后 进行cdq分治,
因为现在第一列已经是递增序列了,如果在第二列中出现了递减那么这两个数就有交点,分治解决,递归左区间
的必然第一列必然小于递归右区间。所以只处理左区间对右区间的影响,两段小区间分别按照 b 从大到小排序,
然后 统计 左区间的b 比右区间大的树状数组更新那个数字。然后更新完成之后查询, 右区间当前的数
(绝对值之差>K无非就是, < x-k 有多少 , > x+k有多少)分别 树状数组进行查询,进行完成之后 ,
数组数组恢复最初状态,回溯 继续处理大区间即可 -
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxn 100010 struct node { int num,a,b; } data[maxn]; bool cp(node x,node y) { return x.a<y.a; }; bool cp2(node x,node y) { return x.b>y.b; }; int tree[maxn],n,k,x; ll ans; int lowbit(int x) { return x&(-x); } void add(int x,int ad) { while(x<=n) { tree[x]+=ad; x+=lowbit(x); } } int query(int x) { int re=0; while(x>0) { re+=tree[x]; x-=lowbit(x); } return re; } void cdq(int l,int r) { if(l==r)return ; int mid=(l+r)>>1; cdq(l,mid); cdq(mid+1,r); sort(data+l,data+1+mid,cp2); sort(data+mid+1,data+1+r,cp2); int i=l,j=mid+1; for(; j<=r; j++) { while(data[i].b>data[j].b&&i<=mid) { add(data[i].num,1); i++; } ans+=query(data[j].num-k-1); if(data[j].num+k<n)ans+=query(n)-query(data[j].num+k); } for(j=l; j<i; j++) add(data[j].num,-1); } int main() { scanf("%d%d",&n,&k); for(int i=1; i<=n; i++) { scanf("%d",&x); data[i].num=i; data[x].a=i; } for(int j=1; j<=n; j++) { scanf("%d",&x); data[x].b=j; } sort(data+1,data+1+n,cp); cdq(1,n); printf("%lld\n",ans); return 0; }