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; }
时间: 2024-10-07 04:12:06