BZOJ 3295 [Cqoi2011]动态逆序对 ——CDQ分治
时间、位置、数字为三个属性。
排序时间,CDQ位置,树状数组处理数字即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define maxn 100005 int a[maxn],q[maxn],n,m,pos[maxn],del[maxn]; struct Event{ int t;//时间 int x;//加入的数 int y;//加入的位置 }b[maxn]; struct Bit_Tree{ int x[maxn]; void add(int i,int f) { for (;i<maxn;i+=i&(-i)) x[i]+=f; } int gs(int i) { int ret=0; for (;i;i-=i&(-i)) ret+=x[i]; return ret; } }BT; bool cmp1(Event a,Event b) {return a.t<b.t;} bool cmp2(Event a,Event b) {return a.y<b.y;} bool cmp3(Event a,Event b) {return a.y>b.y;} ll ans[maxn]; void CDQ(int l,int r,int flag) { if (l==r) return ; int mid=l+r>>1; CDQ(l,mid,flag); CDQ(mid+1,r,flag); int pl=l; if (flag) F(i,mid+1,r) { while (b[pl].y<b[i].y&&pl<=mid) BT.add(b[pl++].x,1); int tmp=BT.gs(n)-BT.gs(b[i].x-1); ans[b[i].t]+=tmp; } else F(i,mid+1,r) { while (b[pl].y>b[i].y&&pl<=mid) BT.add(b[pl++].x,1); int tmp=BT.gs(b[i].x-1); ans[b[i].t]+=tmp; } F(i,l,pl-1) BT.add(b[i].x,-1); sort(b+l,b+r+1,flag?cmp2:cmp3); } int main() { scanf("%d%d",&n,&m); F(i,1,n) scanf("%d",&a[i]),pos[a[i]]=i; F(i,1,m) { scanf("%d",&q[i]); del[q[i]]=1; b[i].t=n-i+1; b[i].x=q[i]; b[i].y=pos[q[i]]; } int now=m; F(i,1,n) if (!del[i]) { b[++now].t=n-now+1; b[now].x=i; b[now].y=pos[i]; } sort(b+1,b+n+1,cmp1); CDQ(1,n,1); sort(b+1,b+n+1,cmp1); CDQ(1,n,0); F(i,2,n) ans[i]+=ans[i-1]; D(i,n,n-m+1) printf("%lld\n",ans[i]); }