C98 CDQ 分治+树状数组 P3157 [CQOI2011] 动态逆序对
视频链接:C98 CDQ 分治+树状数组 P3157 [CQOI2011] 动态逆序对_哔哩哔哩_bilibili
C84 树状数组套权值线段树 P3157 [CQOI2011] 动态逆序对 - 董晓 - 博客园 (cnblogs.com)
// CDQ分治(归并排序)+树状数组 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) x&-x #define mid (l+r>>1) const int N=100005; int n,m,tot; int pos[N],s[N]; long long ans[N]; struct E{ int t,p,v,k; //删除时间,位置,值,贡献 }a[N<<1]; bool cmp(E &a,E &b){ //按位置排序 return a.p<b.p; } void change(int x,int k){ //向后修 while(x<=n)s[x]+=k,x+=lowbit(x); } int query(int x){ //向前查 int t=0; while(x)t+=s[x],x-=lowbit(x); return t; } void CDQ(int l,int r){ //CDQ分治(归并排序) if(l==r) return; CDQ(l,mid); CDQ(mid+1,r); //按时间分裂 int i=l,j=mid+1; while(i<=mid&&j<=r){ if(a[i].p<a[j].p) change(a[i].v,a[i].k),i++; //vi加入树状数组 else ans[a[j].t]+=(query(n)-query(a[j].v))*a[j].k,j++;//>vj的个数 } while(i<=mid) change(a[i].v,a[i].k),i++; while(j<=r) ans[a[j].t]+=(query(n)-query(a[j].v))*a[j].k,j++; for(j=l;j<=mid;j++) change(a[j].v,-a[j].k); //清空树状数组 i=mid,j=r; while(i>=l&&j>mid){ if(a[i].p>a[j].p) change(a[i].v,a[i].k),i--; //vi加入树状数组 else ans[a[j].t]+=query(a[j].v-1)*a[j].k,j--; //<vj的个数 } while(i>=l) change(a[i].v,a[i].k),i--; while(j>mid) ans[a[j].t]+=query(a[j].v-1)*a[j].k,j--; for(j=mid;j>=l;j--) change(a[j].v,-a[j].k); //清空树状数组 sort(a+l,a+r+1,cmp); //按位置排序 } int main(){ scanf("%d%d",&n,&m); for(int i=1,x;i<=n;++i) scanf("%d",&x),pos[x]=i,a[++tot]={0,i,x,1}; for(int i=1,x;i<=m;++i) scanf("%d",&x),a[++tot]={i,pos[x],x,-1}; CDQ(1,tot); //CDQ分治 for(int i=1;i<=m;++i) ans[i]+=ans[i-1]; //前缀和 for(int i=0;i<m;++i) printf("%lld\n",ans[i]); }
// CDQ分治(归并排序)+树状数组 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) x&-x #define mid (l+r>>1) const int N=100005; int n,m,tot; int pos[N],s[N]; long long ans[N]; struct E{ int t,p,v,k; //删除时间,位置,值,贡献 }a[N<<1],b[N<<1]; bool cmp(E &a,E &b){ //按位置排序 return a.p<b.p; } void change(int x,int k){ //向后修 while(x<=n)s[x]+=k,x+=lowbit(x); } int query(int x){ //向前查 int t=0; while(x)t+=s[x],x-=lowbit(x); return t; } void CDQ(int l,int r){ //CDQ分治(归并排序) if(l==r) return; CDQ(l,mid); CDQ(mid+1,r); //按时间分裂 int i=l,j=mid+1,k=l; while(i<=mid&&j<=r){ if(a[i].p<a[j].p) change(a[i].v,a[i].k),b[k++]=a[i++]; //vi加入树状数组 else ans[a[j].t]+=(query(n)-query(a[j].v))*a[j].k,b[k++]=a[j++];//>vj的个数 } while(i<=mid) change(a[i].v,a[i].k),b[k++]=a[i++]; while(j<=r) ans[a[j].t]+=(query(n)-query(a[j].v))*a[j].k,b[k++]=a[j++]; for(j=l;j<=mid;j++) change(a[j].v,-a[j].k); //清空树状数组 i=mid,j=r; while(i>=l&&j>mid){ if(a[i].p>a[j].p) change(a[i].v,a[i].k),i--; //vi加入树状数组 else ans[a[j].t]+=query(a[j].v-1)*a[j].k,j--; //<vj的个数 } while(i>=l) change(a[i].v,a[i].k),i--; while(j>mid) ans[a[j].t]+=query(a[j].v-1)*a[j].k,j--; for(j=mid;j>=l;j--) change(a[j].v,-a[j].k); //清空树状数组 for(i=l;i<=r;i++) a[i]=b[i]; //按位置排序 } int main(){ scanf("%d%d",&n,&m); for(int i=1,x;i<=n;++i) scanf("%d",&x),pos[x]=i,a[++tot]={0,i,x,1}; for(int i=1,x;i<=m;++i) scanf("%d",&x),a[++tot]={i,pos[x],x,-1}; CDQ(1,tot); //CDQ分治 for(int i=1;i<=m;++i) ans[i]+=ans[i-1]; //前缀和 for(int i=0;i<m;++i) printf("%lld\n",ans[i]); }
// CDQ分治(归并排序)+树状数组 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) x&-x #define mid (l+r>>1) const int N=100005; int n,m,tot; int pos[N],s[N]; long long ans[N]; struct E{ int t,p,v,k; //删除时间,位置,值,贡献 }a[N<<1]; bool cmp(E &a,E &b){ //按位置排序 return a.p<b.p; } void change(int x,int k){ //向后修 while(x<=n)s[x]+=k,x+=lowbit(x); } int query(int x){ //向前查 int t=0; while(x)t+=s[x],x-=lowbit(x); return t; } void CDQ(int l,int r){ //CDQ分治(归并排序) if(l==r) return; CDQ(l,mid); CDQ(mid+1,r); //按时间分裂 sort(a+l,a+mid+1,cmp); sort(a+mid+1,a+r+1,cmp); //按位置排序 int i=l,j=mid+1; while(j<=r){ while(i<=mid&&a[i].p<a[j].p) change(a[i].v,a[i].k),i++; //vi加入树状数组 ans[a[j].t]+=(query(n)-query(a[j].v))*a[j].k,j++; //>vj的个数 } for(j=l;j<i;j++) change(a[j].v,-a[j].k); //清空树状数组 i=mid,j=r; while(j>mid){ while(i>=l&&a[i].p>a[j].p) change(a[i].v,a[i].k),i--; //vi加入树状数组 ans[a[j].t]+=query(a[j].v-1)*a[j].k,j--; //<vj的个数 } for(j=mid;j>i;j--) change(a[j].v,-a[j].k); //清空树状数组 } int main(){ scanf("%d%d",&n,&m); for(int i=1,v;i<=n;++i) scanf("%d",&v),pos[v]=i,a[++tot]={0,i,v,1}; for(int i=1,v;i<=m;++i) scanf("%d",&v),a[++tot]={i,pos[v],v,-1}; CDQ(1,tot); //CDQ分治 for(int i=1;i<=m;++i) ans[i]+=ans[i-1]; //前缀和 for(int i=0;i<m;++i) printf("%lld\n",ans[i]); }