[BZOJ3295][CQOI2011]动态逆序对
2018-01-27 21:21
351 查看
此题可以十分简单粗暴地套用树状数组套主席树的模板。
或者:cdq分治。
此题中,原先给出一个数列,之后会删除一些数。但是,呃,删除操作好像有点儿麻烦。反正允许离线,那就当作是初始给出一些数,先把这些数加入序列,之后会再添加一些数。也就是全部反过来算。
可以把每次的答案分成两个部分:原先存在的逆序对+加入这个数新产生的逆序对,那么每次只要算出当前新产生的逆序对,最后算一遍前缀和即可。
加入这个数新产生的逆序对也可以分成两个部分:位置靠前且值比它大的,位置靠后且比它小的。那么总共有三种操作,(1)往序列的某个位置加入一个数,(2)查询比某个数位置靠前且值比它大的数量,(3)查询比某个数位置靠后且值比它小的数量。显然,根据给出的删除顺序,可以得出每个操作的先后顺序,即每个操作的时间。要在cdq分治之前,要先按操作的时间从小到大排序。
在cdq分治中,每次会合并左右两个序列。在合并的时候,如果要查询位置靠前且比它大的,就要先执行位置靠前的操作,位置相同的操作,先执行加入操作,树状数组维护的是值,也就是说cdq分治结束以后,所有操作将按位置从小到大顺序排好。这样不方便查询位置靠后且比它小的。
那么,考虑把所有的操作分成互不影响的两组操作,第一组:所有的操作(1)和操作(2)。第二组:所有的操作(1)和操作(3)。两组操作分别先按时间从小到大排序,第二组操作在cdq分治的时候,先执行值小的操作,树状数组维护的是位置。
最后把两组操作所得结果累计,就得到了每次答案的加入这个数新产生的逆序对这一部分。
代码建议自己完成,实在不行的话,下面那个代码凑合着看吧QAQ
或者:cdq分治。
此题中,原先给出一个数列,之后会删除一些数。但是,呃,删除操作好像有点儿麻烦。反正允许离线,那就当作是初始给出一些数,先把这些数加入序列,之后会再添加一些数。也就是全部反过来算。
可以把每次的答案分成两个部分:原先存在的逆序对+加入这个数新产生的逆序对,那么每次只要算出当前新产生的逆序对,最后算一遍前缀和即可。
加入这个数新产生的逆序对也可以分成两个部分:位置靠前且值比它大的,位置靠后且比它小的。那么总共有三种操作,(1)往序列的某个位置加入一个数,(2)查询比某个数位置靠前且值比它大的数量,(3)查询比某个数位置靠后且值比它小的数量。显然,根据给出的删除顺序,可以得出每个操作的先后顺序,即每个操作的时间。要在cdq分治之前,要先按操作的时间从小到大排序。
在cdq分治中,每次会合并左右两个序列。在合并的时候,如果要查询位置靠前且比它大的,就要先执行位置靠前的操作,位置相同的操作,先执行加入操作,树状数组维护的是值,也就是说cdq分治结束以后,所有操作将按位置从小到大顺序排好。这样不方便查询位置靠后且比它小的。
那么,考虑把所有的操作分成互不影响的两组操作,第一组:所有的操作(1)和操作(2)。第二组:所有的操作(1)和操作(3)。两组操作分别先按时间从小到大排序,第二组操作在cdq分治的时候,先执行值小的操作,树状数组维护的是位置。
最后把两组操作所得结果累计,就得到了每次答案的加入这个数新产生的逆序对这一部分。
代码建议自己完成,实在不行的话,下面那个代码凑合着看吧QAQ
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define lowbit(x) (x&(-x)) inline int getint()//读入优化 { char ch; int res=0; while(ch=getchar(),ch<'0'||ch>'9'); res=ch-48; while(ch=getchar(),ch>='0'&&ch<='9') res=res*10+ch-48; return res; } const int e=3e5+5; struct point { int id,v,t,opt,k; }a[e],t[e],b[e];//id是位置,v是数值。k其实没什么用,然而不知道为什么写进去了。a,b为两组操作 int n,m,real[e],c[e],cnt,num; bool vis[e]; long long ans[e];//逆序对总数可能超过int范围 inline bool cmp(const point &a,const point &b)//排序 { return a.t<b.t||(a.t==b.t&&a.opt<b.opt);//t是时间,opt=1为加入操作,opt=2为询问操作 } inline void init(int x)//树状数组清零 { while(x<=n) { c[x]=0; x+=lowbit(x); } } inline void add(int x,int d)//树状数组单点修改 { while(x<=n) { c[x]+=d; x+=lowbit(x); } } inline int query(int x)//树状数组前缀和查询 { int res=0; while(x) { res+=c[x]; x-=lowbit(x); } return res; } inline void solve(int l,int r)//第一组分治 { if(l==r)return; int mid=(l+r)/2,id1=l,id2,i; id2=mid+1; solve(l,mid); solve(mid+1,r); for(i=l;i<=r;i++) if(id2>r||id1<=mid&&a[id1].id<=a[id2].id)//先执行位置靠前的 { t[i]=a[id1++]; if(t[i].opt==1) add(t[i].v,1); } else { t[i]=a[id2++]; if(t[i].opt==2) ans[t[i].k]+=(long long)query(n)-(long long)query(t[i].v); //查询值比它大的数量 } for(i=l;i<=r;i++) { a[i]=t[i]; init(a[i].v); } } inline void solve2(int l,int r)//第二组分治 { if(l==r)return; int mid=(l+r)/2,id1=l,id2,i; id2=mid+1; solve2(l,mid); solve2(mid+1,r); for(i=l;i<=r;i++) if(id2>r||id1<=mid&&b[id1].v<=b[id2].v)//先执行值较小的 { t[i]=b[id1++]; if(t[i].opt==1) add(t[i].id,1); } else { t[i]=b[id2++]; if(t[i].opt==2) ans[t[i].k]+=(long long)query(n)-(long long)query(t[i].id); //查询位置比它靠后的数量 } for(i=l;i<=r;i++) { b[i]=t[i]; init(b[i].id); } } int main() { int i,x,y; n=getint(); m=getint(); for(i=1;i<=n;i++) { x=getint(); real[x]=i;//x的位置为i } for(i=1;i<=m;i++)//创建操作 { x=getint(); y=real[x];//y为x的位置 vis[x]=true; a[++cnt]=(point){y,x,n-i+1,1,0}; a[++cnt]=(point){y,x,n-i+1,2,n-i+1}; b[++num]=(point){y,x,n-i+1,1,0}; b[++num]=(point){y,x,n-i+1,2,n-i+1}; } int ti=0; for(i=1;i<=n;i++)//创建操作 if(!vis[i]) { a[++cnt]=(point){real[i],i,++ti,1,0}; a[++cnt]=(point){real[i],i,ti,2, 8fdb ti}; b[++num]=(point){real[i],i,ti,1,0}; b[++num]=(point){real[i],i,ti,2,ti}; } sort(a+1,a+cnt+1,cmp);//排序 sort(b+1,b+num+1,cmp); solve(1,cnt); solve2(1,num); for(i=2;i<=n;i++)//做一遍前缀和 ans[i]+=ans[i-1]; for(i=n;i>=n-m+1;i--) printf("%lld\n",ans[i]); return 0; }
相关文章推荐
- 【BZOJ】3295: [Cqoi2011]动态逆序对
- bzoj3295 [Cqoi2011]动态逆序对
- 【bzoj3295】[Cqoi2011]动态逆序对 树套树 线段树套替罪羊树
- 【bzoj3295】[Cqoi2011]动态逆序对 线段树套SBT
- BZOJ 3295: [Cqoi2011]动态逆序对
- BZOJ 3295: [Cqoi2011]动态逆序对
- 【bzoj3295】 CQOI2011动态逆序对 树状数组+主席树
- bzoj 3295: [Cqoi2011]动态逆序对 cdq分治+树状数组
- 【BZOJ】3295: [Cqoi2011]动态逆序对
- bzoj3295[Cqoi2011] 动态逆序对
- [BZOJ3295][CQOI2011]动态逆序对-CDQ分治+树状数组
- 【CDQ分治】BZOJ3295 [Cqoi2011]动态逆序对
- 【分块】bzoj3295 [Cqoi2011]动态逆序对
- 【CQOI2011】bzoj3295 动态逆序对【解法二】
- BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组
- 【BZOJ 3295】 [Cqoi2011]动态逆序对
- [bzoj]3295: [Cqoi2011]动态逆序对 主席树
- bzoj 3295: [Cqoi2011]动态逆序对
- BZOJ 3295 [Cqoi2011]动态逆序对
- bzoj3295: [Cqoi2011]动态逆序对