BZOJ 4919 [Usaco2017 Feb]Why Did the Cow Cross the Road III(cdq分治)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4991

Description

Farmer John is continuing to ponder the issue of cows crossing the road through his farm, introduced

 in the preceding two problems. He realizes now that the threshold for friendliness is a bit more su

btle than he previously considered -- breeds aa and bb are now friendly if |a-b|≤K, and unfriendly 

otherwise.Given the orderings of fields on either side of the road through FJ's farm, please count t

he number of unfriendly crossing pairs of breeds, where a crossing pair of breeds is defined as in t

he preceding problems.

思考过前两个问题后,农民约翰正在继续思考如何对付穿过农场的牛的问题。 他现在意识到,友好的品种的标准

比他以前想的稍微微妙一些 -对于品种a,b,如果|a - b|≤K,现在是友好的。 否则是不友好的。给定这条路两边

的田地的顺序,请计算有多少交叉的不良品种对,其中一对品种在前问题被定义。

 

Input

The first line of input contains N (1≤N≤100,000) and K (0≤K<N). 

The next N lines describe the order, by breed ID, of fields on one side of the road; 

each breed ID is an integer in the range 1…N. The last N lines describe the order, by breed ID, 

of the fields on the other side of the road. Each breed ID appears exactly once in each ordering.

 

Output

Please output the number of unfriendly crossing pairs of breeds.

 

Sample Input

4 1
4
3
2
1
1
4
2
3

Sample Output

2
In this example, breeds 1 and 4 are unfriendly and crossing, as are breeds 1 and 3.

 

题目大意:给定左右两边的号码(号码唯一),左右两边号码相同的连接,如果线条有交叉,且绝对值差值大于k,那么ans++。

题目思路:

将其划分为三维,一维是在左边的位置,二维是在右边的位置,三维是对应的val值,cdq分治即可。

首先对第一维排序 从大到小排序 然后cdq的时候排序第二维从小到大归并 (交叉即为左边大,右边小的边,这样就保证了两维),统计的时候统计前面的只要和我第一维的绝对值差距在k以上的记录答案即可。注意绝对值大于k,所以要加上Query(a[q].val-k-1)和cnt-Query(a[q].val+k)【总数-差值在k以内的】。

AC代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>

using namespace std;

#define FOU(i,x,y) for(int i=x;i<=y;i++)
#define FOD(i,x,y) for(int i=x;i>=y;i--)
#define MEM(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)

const double EXP = 1e-9;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const ll MINF = 0x3f3f3f3f3f3f3f3f;
const double DINF = 0xffffffffffff;
const int mod = 1e9+7;
const int N = 1e5+5;

struct node{
    int x,y;
    int val;
    bool friend operator<(node a,node b){
        return a.x>b.x;
    }
}a[N],tmp[N];

int n,k;
ll ans;


int tree[N]; //tree数组按二进制存,根据n的末尾0的个数存取,树状数组

int lowbit(int x)
{
    return x&(-x);
}

int Query(int x)  //返回1到x的前缀和
{
    if(x<0)
        return 0;
    int res=0;
    while(x)
    {
        res+=tree[x];
        x-=lowbit(x);
    }
    return res;
}

void Add(int x,int v)  //实现a[x]+v;
{
    while(x<=n)        //注意这里是小于等于k,不是n,k是数据范围
    {
        tree[x]+=v;
        x+=lowbit(x);
    }
}

void clearr(int x){
    while(x<=n){
        if(tree[x]==0)
            break;
        tree[x]=0;
        x+=lowbit(x);
    }
}

void cdq(int l,int r){
    if(l>=r) return ;
    int mid = l+r>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    int p=l,q=mid+1,now=l;
    int cnt=0;
    while(p<=mid&&q<=r){
        if(a[p].y<a[q].y){
            Add(a[p].val,1);
            cnt++;
            tmp[now++] = a[p++];
        }
        else{
            int tt=0;
            if(a[q].val+k+1<=n)
                tt=cnt-Query(a[q].val+k);
            ans+=Query(a[q].val-k-1)+tt;
            tmp[now++] = a[q++];
        }
    }
    while(p<=mid){
        Add(a[p].val,1);
        tmp[now++] = a[p++];
    }
    while(q<=r){
        int tt=0;
        if(a[q].val+k+1<=n)
            tt=cnt-Query(a[q].val+k);
        ans+=Query(a[q].val-k-1)+tt;
        tmp[now++] = a[q++];
    }
    for(int i=l;i<=r;i++){
        clearr(a[i].val);
        a[i]=tmp[i];
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    std::ios::sync_with_stdio(false);
    int t;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&t);
        a[t].x = i;
        a[t].val = t;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&t);
        a[t].y = i;
    }
    ans=0;
    sort(a+1,a+1+n);
    cdq(1,n);
    printf("%lld\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值