bzoj3295

cdq分治

我们把每个数都视作插入和询问,那么每个询问就是当前的贡献。。。

事实上这道题可以看做一个三维偏序:(t,v,pos) 插入时间,值,插入位置

两个数当且仅当形成逆序对时是x,y,x的插入时间比y早,x的值比y小,x在y的后面,x的值比y大,x在y的前面。

那么就可以cdq分治了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 400010
#define lowbit(i) i&-i
struct query
{
    int v,id,pos,type;
}q[N];
int n,tot,m;
ll a[N],b[N],tree[N],ans[N],pos[N];
bool flag[N];
vector<query> c;
inline void update(int pos,int delta) {for(int i=pos;i<=n;i+=lowbit(i)) tree[i]+=delta; }
inline ll sum(int pos) {ll ret=0; for(int i=pos;i;i-=lowbit(i)) ret+=tree[i]; return ret;}
inline bool cp1(query x,query y) {if(x.pos!=y.pos) return x.pos<y.pos; return x.type<y.type;}
inline bool cp2(query x,query y) {if(x.pos!=y.pos) return x.pos>y.pos; return x.type<y.type;}
void cdq(int l,int r)
{   
    if(l>=r) return;
    int mid=(l+r)>>1;
    cdq(l,mid); cdq(mid+1,r);
    c.clear();
    for(int i=l;i<=mid;++i) if(q[i].type==1) c.push_back(q[i]);
    for(int i=mid+1;i<=r;++i) if(q[i].type==2) c.push_back(q[i]);
    sort(c.begin(),c.end(),cp1);
    for(int i=0;i<c.size();++i)
    {
        if(c[i].type==1) update(c[i].v,1);
        if(c[i].type==2) ans[c[i].id]+=sum(n)-sum(c[i].v);
    }
    for(int i=0;i<c.size();++i) if(c[i].type==1) update(c[i].v,-1);
    sort(c.begin(),c.end(),cp2);
    for(int i=0;i<c.size();++i)
    {
        if(c[i].type==1) update(c[i].v,1);
        if(c[i].type==2) ans[c[i].id]+=sum(c[i].v-1);
    }
    for(int i=0;i<c.size();++i) if(c[i].type==1) update(c[i].v,-1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
        pos[a[i]]=i;
    }
    for(int i=1;i<=m;++i)
    {
        scanf("%d",&b[i]);
        flag[b[i]]=1;
    }
    int t=0;
    for(int i=1;i<=n;++i) if(!flag[a[i]])
    {
         q[++tot].v=a[i];
         q[tot].type=1;
         q[tot].pos=pos[a[i]];
         q[++tot].v=a[i];
         q[tot].type=2;
         q[tot].pos=pos[a[i]];
         q[tot].id=++t;
    }
    for(int i=m;i;--i)
    {
        q[++tot].v=b[i];
        q[tot].pos=pos[b[i]];
        q[tot].type=1;
        q[++tot].v=b[i];
        q[tot].pos=pos[b[i]];
        q[tot].type=2;
        q[tot].id=++t;
    }
    cdq(1,tot);
    for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
    for(int i=n;i>=n-m+1;--i) printf("%lld\n",ans[i]);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/19992147orz/p/6387014.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值