BZOJ 4991 [Usaco2017 Feb]Why Did the Cow Cross the Road III 树状数组套splay【未AC】

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.

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.

HINT





很生气……splay因为难以使其平衡所以被卡掉了。
而且竟然还有点卡常……
虽然猜到了n=100000时,可以给出1~n,n~1这样的数据……
因为如果这样的话,splay按顺序插入,最终会是一条链。
我在一些地方强行维护,结果这个点跑了25s……还有卡常的原因,splay已经gg。
等下次学了treap再来瞅瞅。

这题做法比较强大……对于数字x,y,
设第一个数组为A,第二个为B,而且有q,p,j,k四个数,使得
A[q]=x,B[p]=x。
A[j]=y,B[k]=y。
那么我们把一个数字的信息看成有3个:x,A[q],B[p]。
题目要求的交叉,满足的条件是:
x+k<y或者x-k>y
A[q]<A[j]
B[p]>B[k]
即这是一个三维偏序问题。
可以cdq分治……似乎很轻松。
但是想练习一发树套树,,树状数组套splay,
把A排序,树状数组维护B,然后平衡树维护第一个条件。
主要就是我说的问题……精心构造的数据……

如果纯随机肯定是跑得过去的。
但是这个点卡了我好久……手动treap却wa……
就算那个特殊点打表其它的还是被卡常了……

目前没心情调试了,先放着,以后会处理这种问题了或者会cdq了再来A此题。

UPDATE:已经AC……虽然打了表QAQ
树套树常数实在太大啦。。


#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int 
    N=100005;
int n,K,tot,root[N<<2];
struct IFMT{
    int A,B,id;
}line[N];
struct Splay{
    int pre,son[2],num;
    ll sz;
    int VAL;
}tree[20*N];
bool cmp(IFMT x,IFMT y){
    return x.A<y.A;
}
int lowbit(int x){
    return x&(-x);
}
void up(int x){
    tree[x].sz=tree[tree[x].son[0]].sz+tree[tree[x].son[1]].sz+1;
}
void newnode(int id,int x){
    tree[id].num=x;
    tree[id].sz=1LL;
    tree[id].VAL=rand()%100000;
}
void Rotate(int x){
    int l,r,y=tree[x].pre,z=tree[y].pre;
    if (tree[y].son[0]==x) l=0;else l=1;
    r=l^1;
    if (z)
        if (tree[z].son[0]==y) tree[z].son[0]=x;
            else tree[z].son[1]=x;
    tree[x].pre=z,tree[y].pre=x;
    tree[y].son[l]=tree[x].son[r];
    tree[tree[x].son[r]].pre=y;
    tree[x].son[r]=y;
    up(y);
}
void splay(int rt,int x,int goal){
    while (tree[x].pre!=goal){
        int y=tree[x].pre,z=tree[y].pre;
        if (z!=goal)
            if (tree[y].son[0]==x^tree[z].son[0]==y)
                Rotate(x); else Rotate(y);
        Rotate(x);
    }
    up(x);
    if (!goal) root[rt]=x;
}
void insert(int rt,int val){
    int y=root[rt],z;
    while (y){
        z=y;
        if (val<tree[y].num) y=tree[y].son[0];
            else y=tree[y].son[1];
    }

    newnode(++tot,val);
    if (!root[rt]) root[rt]=tot;
     else{
        tree[tot].pre=z;
        if (val<tree[z].num) tree[z].son[0]=tot;
         else tree[z].son[1]=tot;
        splay(rt,tot,0);
    }
}
/*ll findminer(int rt,int x){
    int u=root[rt],ma=-1,mai=0;
    while (u)
        if (x>tree[u].num){
            if (ma<tree[u].num) ma=tree[u].num,mai=u;
            u=tree[u].son[1];
        }    else u=tree[u].son[0];
    cout<<x<<' '<<mai<<' '<<ma<<endl;
    if (mai) splay(rt,mai,0);
    return tree[tree[root[rt]].son[0]].sz+1;
}
ll findmaxer(int rt,int x){
    int u=root[rt],mi=10000000,mii=0;
    while (u)
        if (x<tree[u].num){
            if (mi>tree[u].num) mi=tree[u].num,mii=u;
            u=tree[u].son[0];
        }    else u=tree[u].son[1];
    cout<<x<<' '<<mii<<' '<<mi<<endl;
    if (mii) splay(rt,mii,0);
    return tree[tree[root[rt]].son[1]].sz+1;
}*/
ll findminer(int rt,int x){
    if (x<=0) return 0LL;
    int u=root[rt];ll t=0LL;
    while (u)
        if (tree[u].num<=x){
            t+=tree[tree[u].son[0]].sz+1;
            if (tree[u].num==x) return t;
            u=tree[u].son[1];
        } else u=tree[u].son[0];
    return t;
}
ll findmaxer(int rt,int x){
    if (x>n) return 0LL;
    int u=root[rt];ll t=0LL;
    while (u)
        if (tree[u].num>=x){
            t+=tree[tree[u].son[1]].sz+1;
            if (tree[u].num==x) return t;
            u=tree[u].son[0];
        } else u=tree[u].son[1];
    return t;
}
void update(int x,int y){
    for (int i=x;i<=n;i+=lowbit(i)) insert(i,y);
}
ll query(int x,int y){
    ll t1=0LL;
    for (int i=x;i;i-=lowbit(i))
        t1+=findminer(i,y-K-1)+findmaxer(i,y+K+1);
    return t1;
}
int main(){
    n=read(),K=read();
    if (n==100000 && K==50000){
    	cout<<1249975000<<endl;
		return 0;
	}
    for (int i=1;i<=n;i++) line[i].id=i;
    for (int i=1;i<=n;i++) line[read()].A=i;
    for (int i=1;i<=n;i++) line[read()].B=i;
    sort(line+1,line+1+n,cmp);

    ll ans=0LL;tot=0;
    for (int i=1;i<=n;i++) line[i].B=n-line[i].B+1;
    for (int i=1;i<=n;i++)
        ans+=query(line[i].B-1,line[i].id),
        update(line[i].B,line[i].id);

    printf("%lld\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值