bzoj 3295: [Cqoi2011]动态逆序对 cdq分治+树状数组
2016-10-24 19:30
513 查看
题目大意
给出1-n的一个排列和m个操作,每个操作有一个数字x表示在序列中把x这个数删掉,并且求在删掉x前该序列中有多少个逆序对。n<=100000,m<=50000
分析
这题看完题后就想到了可以用树套树来搞,但是比较麻烦(其实也不是很麻烦)并且对于n<=100000,m<=50000的数据范围如果用nlog^2的复杂度去做的话会跑的很慢,于是就选择了新学的cdq分治。先一开始往序列里面插入没被删除的数,然后从后往前的顺序处理操作。把每个操作拆分成两个操作,一个是插入,一个是询问,顺序不限。
那么问题就转换成了对于三元组(x,y,z)的处理,x是操作序号,y是下标,z是具体数值。对于这种问题一般的处理方式都是第一维直接排序,第二维cdq分治掉,第三维树状数组。
具体的就跟bzoj 3262一样啦。
注意要开long long
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define N 100005 #define ll long long using namespace std; int c ,a ,pos ,n,m,cnt,tot,vis ,num ,ans ; struct data{int x,pos,op,id;}q[N*10],t[N*10]; void ins(int x,int y) { while (x<=n) { c[x]+=y; x+=x&(-x); } } int query(int x) { int ans=0; while (x) { ans+=c[x]; x-=x&(-x); } return ans; } void cdq(int l,int r) { if (l>=r) return; int mid=(l+r)/2; cdq(l,mid);cdq(mid+1,r); for (int j=mid+1,i=l;j<=r;j++) { while (q[i].pos<q[j].pos&&i<=mid) { if (q[i].op==1) ins(q[i].x,1); i++; } if (q[j].op==2) ans[q[j].id]+=query(q[j].x-1); } for (int i=l,j=mid+1;j<=r;j++) while (q[i].pos<q[j].pos&&i<=mid) { if (q[i].op==1) ins(q[i].x,-1); i++; } for (int i=mid,j=r;j>mid;j--) { while (q[i].pos>q[j].pos&&i>=l) { if (q[i].op==1) ins(q[i].x,1); i--; } if (q[j].op==2) ans[q[j].id]+=query(n)-query(q[j].x); } for (int i=mid,j=r;j>mid;j--) while (q[i].pos>q[j].pos&&i>=l) { if (q[i].op==1) ins(q[i].x,-1); i--; } int i=l,j=mid+1,k=l; while (i<=mid||j<=r) if (q[i].pos<q[j].pos&&i<=mid||j>r) t[k++]=q[i++]; else t[k++]=q[j++]; for (int i=l;i<=r;i++) q[i]=t[i]; } 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",&num[i]); vis[pos[num[i]]]=1; } ll sum=0; for (int i=1;i<=n;i++) { sum+=query(n)-query(a[i]); ins(a[i],1); } for (int i=1;i<=n;i++) ins(a[i],-1); for (int i=1;i<=n;i++) if (!vis[i]) { q[++tot].op=1; q[tot].pos=i; q[tot].x=n-a[i]+1; } for (int i=m;i>=1;i--) { q[++tot].op=1; q[tot].pos=pos[num[i]]; q[tot].x=n-num[i]+1; q[++tot].op=2; q[tot].pos=pos[num[i]]; q[tot].x=n-num[i]+1; q[tot].id=++cnt; } cdq(1,tot); for (int i=cnt;i>=1;i--) { printf("%lld\n",sum); sum-=ans[i]; } return 0; }
相关文章推荐
- [BZOJ3295][CQOI2011]动态逆序对-CDQ分治+树状数组
- BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组
- Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对
- 【BZOJ3295】【CQOI2011】动态逆序对
- [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树
- bzoj3295[Cqoi2011] 动态逆序对
- 【BZOJ】3295: [Cqoi2011]动态逆序对
- bzoj3295: [Cqoi2011]动态逆序对 树状数组套线段树
- [BZOJ 3295] CQOI 2011 动态逆序对 · 分块 & 逆序对
- 【BZOJ3295】【Cqoi2011】动态逆序对
- BZOJ 3295: [Cqoi2011]动态逆序对 [CDQ分治]
- 【bzoj3295】[Cqoi2011]动态逆序对 树套树 线段树套替罪羊树
- [BZOJ 3295] Cqoi2011 动态逆序对
- 主席树初探 & bzoj 3295: [Cqoi2011] 动态逆序对 题解
- 【bzoj3295】 Cqoi2011—动态逆序对
- BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树
- 【bzoj3295】【Cqoi2011】【动态逆序对】【树状数组套平衡树】
- BZOJ 3295 CQOI 2011 动态逆序对 线段树套Treap
- 【BZOJ 3295】[Cqoi2011]动态逆序对
- 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治