C98 CDQ 分治+树状数组 P3157 [CQOI2011] 动态逆序对

视频链接:C98 CDQ 分治+树状数组 P3157 [CQOI2011] 动态逆序对_哔哩哔哩_bilibili

 

 

 

C84 树状数组套权值线段树 P3157 [CQOI2011] 动态逆序对 - 董晓 - 博客园 (cnblogs.com)

Luogu P3157 [CQOI2011] 动态逆序对

// 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]);
}

 

posted @ 2024-02-04 20:18  董晓  阅读(281)  评论(0编辑  收藏  举报