题解- P3658 Why Did the Cow Cross the Road III P

  • 题目大意

很小清新。就是给你两个排列使得两个排列中相同的数字两边相连。最后问你存在多少对数对满足有交叉且

我们可以将题目转化的更加小清新。因为要有交显然满足以及为该元素在排列中的位置

这样我们就可以设一个三元组满足

于是这样就转换为一个三维偏序的简单问题,三维偏序见戳这里

然后我们考虑单次计算的贡献显然为这段区间里的答案,简单容斥即可

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,a,b) for ( int i=(a);i>=(b);i-- )
#define FOR(i,t) for ( int i=head[t];i;i=e[i].nex )
#define int long long
#define db double
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define lowbit(x) x&(-x)
using namespace std;

namespace IO {
    #define gc getchar
    #define pt putchar
    inline int read() {
        int sum=0,ff=1; char ch=gc();
        while(!isdigit(ch)) {
            if(ch=='-') ff=-1;
            ch=gc();
        }
        while(isdigit(ch))
            sum=sum*10+(ch^48),ch=gc();
        return sum*ff;
    }

    inline void write(int x) {
        if(x<0) pt('-'),x=-x;
        if(x>9) write(x/10);
        pt(x%10|48);
    }

    inline void wln(int x) {
        write(x); pt('\n');
    }

    inline void wrn(int x) {
        write(x); pt(' ');
    }
}

using namespace IO;

const int N=1000005;

int n,m,c[N*2],bo[N],ans;

struct number {
    int x,y,z;
};
number a[N],tmp[N];

inline bool cmpy(number a,number b) {
    if(a.y==b.y) return a.z<b.z;
    return a.y>b.y;
}

inline bool cmpx(number a,number b) {
    if(a.x==b.x) {
        if(a.y==b.y) return a.z<b.z;
        return a.y>b.y;
    }
    return a.x<b.x;
}
//三维排序

inline void add(int x,int val) {
    while(x<=n) {
        c[x]+=val;
        x+=lowbit(x);
    }
}

inline int query(int x) {
    int ret=0;
    x=min(x,n);
    x=max(x,0ll);
    //注意边界,被坑了好久
    while(x) {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}

inline void cdq(int l,int r) {
//cdq模板
    if(l==r) return;
    int mid=(l+r)/2;
    cdq(l,mid);
    cdq(mid+1,r);
    sort(a+l,a+mid+1,cmpy);
    sort(a+mid+1,a+r+1,cmpy);
    int i=mid+1,j=l;
    for (;i<=r;i++) {
        while(j<=mid&&a[j].y>a[i].y) {
            add(a[j].z,1);
            j++;
        }
        ans+=query(a[i].z-m-1)+query(n)-query(a[i].z+m);
       //计算单次贡献
    }
    For(i,l,j-1) add(a[i].z,-1);//清空树状数组
}

signed main() {
    n=read();
    m=read();
    For(i,1,n) bo[read()]=i;
    //映射数组
    For(i,1,n) {
        int x=read();
        a[i]=(number){bo[x],i,x};
        //建立三元组
    }
    sort(a+1,a+n+1,cmpx);
    cdq(1,n);
    wln(ans);
    return 0;
}